package org.simpleflatmapper.reflect.asm; import org.simpleflatmapper.ow2asm.ClassWriter; import org.simpleflatmapper.ow2asm.MethodVisitor; import org.simpleflatmapper.ow2asm.Opcodes; import org.simpleflatmapper.reflect.Getter; import org.simpleflatmapper.reflect.primitive.IntGetter; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetterBuilder implements Opcodes { private static final String GETTER_TYPE = AsmUtils.toAsmType(Getter.class); private static final String ORG_SFM_REFLECT_PRIMITIVE = AsmUtils.toAsmType(IntGetter.class.getPackage().getName()); public static byte[] createObjectGetter(final String className, final Field field) throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; Class<?> target = field.getDeclaringClass(); Class<?> property = field.getType(); String targetType = toType(target); String propertyType = toType(property); String classType = toType(className); cw.visit( V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;L" + GETTER_TYPE + "<L" + targetType + ";" + AsmUtils.toTargetTypeDeclaration(propertyType) + ">;", "java/lang/Object", new String[] {GETTER_TYPE}); { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, targetType, field.getName(), AsmUtils.toTargetTypeDeclaration(propertyType)); mv.visitInsn(ARETURN); mv.visitMaxs(1, 2); mv.visitEnd(); } appendBridge(cw, targetType, propertyType, classType); appendToString(cw); cw.visitEnd(); return AsmUtils.writeClassToFile(className, cw.toByteArray()); } public static byte[] createObjectGetter(final String className, final Method method) throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; Class<?> target = method.getDeclaringClass(); Class<?> property = method.getReturnType(); String targetType = toType(target); String propertyType = toType(property); String classType = toType(className); cw.visit( V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;L" + GETTER_TYPE + "<L" + targetType + ";" + AsmUtils.toTargetTypeDeclaration(propertyType) + ">;", "java/lang/Object", new String[] {GETTER_TYPE}); { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); AsmUtils.invoke(mv, target, method.getName(), "()" + AsmUtils.toTargetTypeDeclaration(propertyType)); mv.visitInsn(ARETURN); mv.visitMaxs(1, 2); mv.visitEnd(); } appendBridge(cw, targetType, propertyType, classType); appendToString(cw); cw.visitEnd(); return AsmUtils.writeClassToFile(className, cw.toByteArray()); } private static void appendBridge(ClassWriter cw, String targetType, String propertyType, String classType) { MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, targetType); mv.visitMethodInsn(INVOKEVIRTUAL, classType, "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), false); mv.visitInsn(ARETURN); mv.visitMaxs(2, 2); mv.visitEnd(); } public static byte[] createPrimitiveGetter(String className, Field field) throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; Class<?> target = field.getDeclaringClass(); Class<?> primitive = field.getType(); Class<?> property = AsmUtils.wrappers.get(primitive); String targetType = toType(target); String primitiveType = AsmUtils.primitivesType.get(primitive); String propertyType = toType(property); String classType = toType(className); String methodSuffix = property.getSimpleName(); if ("Integer".equals(methodSuffix)) { methodSuffix = "Int"; } String getMethod = "get" + methodSuffix; cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;" + "L" + GETTER_TYPE + "<L" + targetType + ";" + AsmUtils.toTargetTypeDeclaration(propertyType) + ">;" + "L" + ORG_SFM_REFLECT_PRIMITIVE + methodSuffix + "Getter<L" + targetType + ";>;", "java/lang/Object", new String[] {GETTER_TYPE, ORG_SFM_REFLECT_PRIMITIVE + "/" + methodSuffix + "Getter" }); { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, getMethod, "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + primitiveType , null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, targetType, field.getName(), primitiveType); mv.visitInsn(AsmUtils.returnOps.get(primitive)); mv.visitMaxs(1, 2); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, targetType, field.getName(), primitiveType); mv.visitMethodInsn(INVOKESTATIC, propertyType, "valueOf", "(" + primitiveType + ")L" + propertyType + ";" , false); mv.visitInsn(ARETURN); mv.visitMaxs(1, 2); mv.visitEnd(); } appendPrimitiveBridges(cw, primitive, targetType, primitiveType, propertyType, classType, getMethod); appendToString(cw); cw.visitEnd(); return AsmUtils.writeClassToFile(className, cw.toByteArray()); } public static byte[] createPrimitiveGetter(String className, Method method) throws Exception { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); MethodVisitor mv; Class<?> target = method.getDeclaringClass(); Class<?> primitive = method.getReturnType(); Class<?> property = AsmUtils.wrappers.get(primitive); String targetType = toType(target); String primitiveType = AsmUtils.primitivesType.get(primitive); String propertyType = toType(property); String classType = toType(className); String methodSuffix = property.getSimpleName(); if ("Integer".equals(methodSuffix)) { methodSuffix = "Int"; } String getMethod = "get" + methodSuffix; cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "Ljava/lang/Object;" + "L" + GETTER_TYPE + "<L" + targetType + ";" + AsmUtils.toTargetTypeDeclaration(propertyType) + ">;" + "L" + ORG_SFM_REFLECT_PRIMITIVE + methodSuffix + "Getter<L" + targetType + ";>;", "java/lang/Object", new String[] {GETTER_TYPE, ORG_SFM_REFLECT_PRIMITIVE + "/" + methodSuffix + "Getter" }); { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, getMethod, "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + primitiveType , null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); AsmUtils.invoke(mv, target, method.getName(), "()" + primitiveType); mv.visitInsn(AsmUtils.returnOps.get(primitive)); mv.visitMaxs(1, 2); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); AsmUtils.invoke(mv, target, method.getName(), "()" + primitiveType); mv.visitMethodInsn(INVOKESTATIC, propertyType, "valueOf", "(" + primitiveType + ")L" + propertyType + ";" , false); mv.visitInsn(ARETURN); mv.visitMaxs(1, 2); mv.visitEnd(); } appendPrimitiveBridges(cw, primitive, targetType, primitiveType, propertyType, classType, getMethod); appendToString(cw); cw.visitEnd(); return AsmUtils.writeClassToFile(className, cw.toByteArray()); } private static void appendPrimitiveBridges(ClassWriter cw, Class<?> primitive, String targetType, String primitiveType, String propertyType, String classType, String getMethod) { MethodVisitor mv; { mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, getMethod, "(Ljava/lang/Object;)" + primitiveType, null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, targetType); mv.visitMethodInsn(INVOKEVIRTUAL, classType , getMethod, "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + primitiveType, false); mv.visitInsn(AsmUtils.returnOps.get(primitive)); mv.visitMaxs(2, 2); mv.visitEnd(); } { mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, new String[] { "java/lang/Exception" }); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, targetType ); mv.visitMethodInsn(INVOKEVIRTUAL, classType , "get", "(" + AsmUtils.toTargetTypeDeclaration(targetType) + ")" + AsmUtils.toTargetTypeDeclaration(propertyType), false); mv.visitInsn(ARETURN); mv.visitMaxs(2, 2); mv.visitEnd(); } } private static void appendToString(ClassWriter cw) { MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); mv.visitCode(); mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false); mv.visitVarInsn(ASTORE, 1); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSimpleName", "()Ljava/lang/String;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitLdcInsn("{"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitLdcInsn("}"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); mv.visitInsn(ARETURN); mv.visitMaxs(2, 1); mv.visitEnd(); } private static String toType(Class<?> target) { String name = target.getName(); return toType(name); } private static String toType(String name) { return name.replace('.', '/'); } }