package jef.accelerator.bean; import static jef.accelerator.asm.ASMUtils.getDesc; import static jef.accelerator.asm.ASMUtils.getMethodDesc; import static jef.accelerator.asm.ASMUtils.getType; import static jef.accelerator.asm.ASMUtils.iconst; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import jef.accelerator.asm.ASMUtils; import jef.accelerator.asm.ClassWriter; import jef.accelerator.asm.Label; import jef.accelerator.asm.MethodVisitor; import jef.accelerator.asm.Opcodes; import jef.accelerator.asm.Type; import jef.tools.reflect.BeanUtils; import jef.tools.reflect.ConvertUtils; public abstract class ClassGenerator implements Opcodes { protected Class<?> beanClass; protected String beanType; protected String accessorName; protected String accessorType; protected ClassLoader cl; protected FieldInfo[] fields; protected ClassGenerator(Class<?> javaBean, String accessorName, FieldInfo[] fields, ClassLoader cl) { this.beanClass = javaBean; this.beanType = getType(beanClass); this.accessorName = accessorName; this.accessorType = accessorName.replace('.', '/'); this.fields = fields; this.cl = cl; } abstract byte[] generate(); public void generatePublicMethods(ClassWriter cw) { generateCopy(cw); generateConvert(cw); generateFromMap(cw); { MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "newInstance", getMethodDesc(Object.class), null, null); mw.visitTypeInsn(NEW, beanType); try { // 运行空构造方法 if (beanClass.getDeclaredConstructor() != null) { mw.visitInsn(DUP); mw.visitMethodInsn(INVOKESPECIAL, beanType, "<init>", "()V"); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } mw.visitInsn(ARETURN); mw.visitMaxs(2, 1); mw.visitEnd(); } { MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getType", getMethodDesc(Class.class), null, null); mw.visitLdcInsn(Type.getType(beanClass));// S1 mw.visitInsn(ARETURN); mw.visitMaxs(1, 1); mw.visitEnd(); } } private void generateFromMap(ClassWriter cw) { MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "fromMap", getMethodDesc(Object.class, Map.class), null, null); mw.visitTypeInsn(NEW, beanType);//S1 L2 try { // 运行空构造方法 if (beanClass.getDeclaredConstructor() != null) { mw.visitInsn(DUP); mw.visitMethodInsn(INVOKESPECIAL, beanType, "<init>", "()V"); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } mw.visitVarInsn(ASTORE, 2);// L3 S0 for (int i = 0; i < fields.length; i++) { FieldInfo fi = fields[i]; mw.visitVarInsn(ALOAD, 2);// S1 the object mw.visitVarInsn(ALOAD, 1);// S2 the map mw.visitLdcInsn(fi.getName());// S3 key mw.visitMethodInsn(INVOKEINTERFACE, getType(Map.class), "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); //S2 value if (fi.isPrimitive()) { Label notnull=new Label(); Label end=new Label(); mw.visitInsn(DUP); // S3 mw.visitJumpInsn(IFNONNULL, notnull);//S2 mw.visitInsn(POP2);//S0 mw.visitJumpInsn(GOTO,end); mw.visitLabel(notnull); Class<?> wrpped=BeanUtils.toWrapperClass(fi.getRawType()); mw.visitTypeInsn(CHECKCAST, getType(wrpped)); //S2 value ASMUtils.doUnwrap(mw, fi.getRawType(), wrpped); this.generateInvokeMethod(mw, fi.getSetter());//S0 if (fi.getSetter().getReturnType() != void.class) { mw.visitInsn(POP); } mw.visitLabel(end); }else { mw.visitTypeInsn(CHECKCAST, getType(fi.getRawType())); //S2 value this.generateInvokeMethod(mw, fi.getSetter()); if (fi.getSetter().getReturnType() != void.class) { mw.visitInsn(POP); } } } mw.visitVarInsn(ALOAD, 2); mw.visitInsn(ARETURN); mw.visitMaxs(3,3); mw.visitEnd(); mw = cw.visitMethod(ACC_PUBLIC, "fromMap2", getMethodDesc(Object.class, Map.class), null, null); mw.visitTypeInsn(NEW, beanType);//S1 L2 try { // 运行空构造方法 if (beanClass.getDeclaredConstructor() != null) { mw.visitInsn(DUP); mw.visitMethodInsn(INVOKESPECIAL, beanType, "<init>", "()V"); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } mw.visitVarInsn(ASTORE, 2);// L3 S0 for (int i = 0; i < fields.length; i++) { FieldInfo fi = fields[i]; mw.visitVarInsn(ALOAD, 2);// S1 the object mw.visitVarInsn(ALOAD, 1);// S2 the map mw.visitLdcInsn(fi.getName());// S3 key mw.visitMethodInsn(INVOKEINTERFACE, getType(Map.class), "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); //S2 value pushGenericType(mw,fi.getRawType(),fi.getName()); mw.visitMethodInsn(INVOKESTATIC, getType(ConvertUtils.class), "toProperType", "(Ljava/lang/Object;Ljava/lang/reflect/Type;)Ljava/lang/Object;"); //S2 value if (fi.isPrimitive()) { Label notnull=new Label(); Label end=new Label(); mw.visitInsn(DUP); // S3 mw.visitJumpInsn(IFNONNULL, notnull);//S2 mw.visitInsn(POP2);//S0 mw.visitJumpInsn(GOTO,end); mw.visitLabel(notnull); Class<?> wrpped=BeanUtils.toWrapperClass(fi.getRawType()); mw.visitTypeInsn(CHECKCAST, getType(wrpped)); //S2 value ASMUtils.doUnwrap(mw, fi.getRawType(), wrpped); this.generateInvokeMethod(mw, fi.getSetter());//S0 if (fi.getSetter().getReturnType() != void.class) { mw.visitInsn(POP); } mw.visitLabel(end); }else { mw.visitTypeInsn(CHECKCAST, getType(fi.getRawType())); //S2 value this.generateInvokeMethod(mw, fi.getSetter()); if (fi.getSetter().getReturnType() != void.class) { mw.visitInsn(POP); } } } mw.visitVarInsn(ALOAD, 2); mw.visitInsn(ARETURN); mw.visitMaxs(4,3); mw.visitEnd(); } private void pushGenericType(MethodVisitor mw,Class<?> rawType,String pname) { if(rawType.isPrimitive()) { String s = rawType.getName(); // int 226 // short 215 // long 221 // boolean 222 // float 219 // double 228 // char 201 // byte 237 switch (s.charAt(1) + s.charAt(2)) { case 226: mw.visitFieldInsn(GETSTATIC, getType(Integer.class), "TYPE", "Ljava/lang/Class;"); break; case 215: mw.visitFieldInsn(GETSTATIC, getType(Short.class), "TYPE", "Ljava/lang/Class;"); break; case 221: mw.visitFieldInsn(GETSTATIC, getType(Long.class), "TYPE", "Ljava/lang/Class;"); break; case 222: mw.visitFieldInsn(GETSTATIC, getType(Boolean.class), "TYPE", "Ljava/lang/Class;"); break; case 219: mw.visitFieldInsn(GETSTATIC, getType(Float.class), "TYPE", "Ljava/lang/Class;"); break; case 228: mw.visitFieldInsn(GETSTATIC, getType(Double.class), "TYPE", "Ljava/lang/Class;"); break; case 201: mw.visitFieldInsn(GETSTATIC, getType(Character.class), "TYPE", "Ljava/lang/Class;"); break; case 237: mw.visitFieldInsn(GETSTATIC, getType(Byte.class), "TYPE", "Ljava/lang/Class;"); break; } }else { mw.visitVarInsn(ALOAD, 0); mw.visitLdcInsn(pname);// S2 mw.visitMethodInsn(INVOKEVIRTUAL, accessorType, "getGenericType", getMethodDesc(java.lang.reflect.Type.class,String.class)); } } private void generateConvert(ClassWriter cw) { MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "convert", getMethodDesc(Map.class, Object.class), null, null); // L2 S0 Label checkArg = new Label(); mw.visitVarInsn(ALOAD, 1);// S1 mw.visitJumpInsn(IFNONNULL, checkArg); mw.visitInsn(Opcodes.ACONST_NULL); mw.visitInsn(ARETURN); mw.visitLabel(checkArg); mw.visitVarInsn(ALOAD, 1);// S1 mw.visitTypeInsn(CHECKCAST, beanType); mw.visitVarInsn(ASTORE, 2);// L3 S0 mw.visitTypeInsn(NEW, getType(HashMap.class));// S1 mw.visitInsn(DUP); // S2 iconst(mw, fields.length); // S3 mw.visitMethodInsn(INVOKESPECIAL, getType(HashMap.class), "<init>", "(I)V");// S1 mw.visitVarInsn(ASTORE, 3);// L4 S0 for (int i = 0; i < fields.length; i++) { FieldInfo fi = fields[i]; mw.visitVarInsn(ALOAD, 3);// S1 mw.visitLdcInsn(fi.getName());// S2 mw.visitVarInsn(ALOAD, 2);// S3 Method getter = fi.getGetter(); generateInvokeMethod(mw, getter);// S3 if (fi.isPrimitive()) { ASMUtils.doWrap(mw, fi.getRawType()); } mw.visitMethodInsn(INVOKEVIRTUAL, getType(HashMap.class), "put", getMethodDesc(Object.class, Object.class, Object.class)); mw.visitInsn(POP); } mw.visitVarInsn(ALOAD, 3); mw.visitInsn(ARETURN); mw.visitMaxs(4, 4); mw.visitEnd(); } private void generateCopy(ClassWriter cw) { MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "copy", getMethodDesc(Void.TYPE, Object.class, Object.class), null, null); Label checkArg2 = new Label(); Label checkOver = new Label(); mw.visitVarInsn(ALOAD, 1); mw.visitJumpInsn(IFNONNULL, checkArg2); mw.visitInsn(RETURN); mw.visitLabel(checkArg2); mw.visitVarInsn(ALOAD, 2); mw.visitJumpInsn(IFNONNULL, checkOver); mw.visitInsn(RETURN); mw.visitLabel(checkOver); mw.visitVarInsn(ALOAD, 1); mw.visitTypeInsn(CHECKCAST, beanType); mw.visitVarInsn(ASTORE, 3); mw.visitVarInsn(ALOAD, 2); mw.visitTypeInsn(CHECKCAST, beanType); mw.visitVarInsn(ASTORE, 4); for (int i = 0; i < fields.length; i++) { mw.visitVarInsn(ALOAD, 4); mw.visitVarInsn(ALOAD, 3); this.generateInvokeMethod(mw, fields[i].getGetter()); this.generateInvokeMethod(mw, fields[i].getSetter()); if (fields[i].getSetter().getReturnType() != void.class) { mw.visitInsn(POP); } } mw.visitInsn(RETURN); mw.visitMaxs(3, 5); mw.visitEnd(); } protected void generateInvokeMethod(MethodVisitor mw, Method m) { mw.visitMethodInsn(INVOKEVIRTUAL, getType(m.getDeclaringClass()), m.getName(), getDesc(m)); } }