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 java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import jef.accelerator.asm.ASMUtils;
import jef.accelerator.asm.ClassWriter;
import jef.accelerator.asm.FieldVisitor;
import jef.accelerator.asm.Label;
import jef.accelerator.asm.MethodVisitor;
import jef.tools.reflect.BeanUtils;
import jef.tools.reflect.UnsafeUtils;
final class ASMHashGenerator extends ClassGenerator {
@SuppressWarnings("rawtypes")
private Class[] properTyClz;
public ASMHashGenerator(Class<?> javaBean, String accessorName, FieldInfo[] fields,ClassLoader cl) {
super(javaBean,accessorName,fields,cl);
this.properTyClz = new Class[fields.length];
}
public byte[] generate() {
generatePropertyClz();
return generateMain();
}
private byte[] generateMain() {
ClassWriter cw = new ClassWriter(0);
String parentClz = getType(HashBeanAccessor.class);
String mapType=getType(Map.class);
cw.visit(V1_5, ACC_PUBLIC + ACC_FINAL, accessorName, null,parentClz, new String[] {});
{
FieldVisitor fw = cw.visitField(ACC_PRIVATE | ACC_FINAL, "fields", getDesc(java.util.Map.class),null, null);
fw.visitEnd();
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getPropertyNames", "()Ljava/util/Collection;",null, null);
mw.visitVarInsn(ALOAD, 0);
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;");
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "keySet", "()Ljava/util/Set;");
mw.visitInsn(ARETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
}
// //构造器
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,null);
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, parentClz, "<init>", "()V");//S0
String hashMapType=getType(HashMap.class);
mw.visitTypeInsn(NEW, hashMapType); //S1=map
mw.visitInsn(DUP); //S2=map
ASMUtils.iconst(mw, fields.length*4/3+1); //S3=int
mw.visitMethodInsn(INVOKESPECIAL, hashMapType, "<init>", "(I)V"); //S1=map
mw.visitVarInsn(ASTORE, 1); //S0
mw.visitVarInsn(ALOAD, 0); //S1=this
mw.visitVarInsn(ALOAD, 1); //S1=map
mw.visitFieldInsn(PUTFIELD, accessorName, "fields", "Ljava/util/Map;"); //s清空
for(int i=0;i<fields.length;i++){
mw.visitVarInsn(ALOAD, 1); //S1=map
FieldInfo fi=fields[i];
mw.visitLdcInsn(fi.getName()); //S2=string
String pType=getType(properTyClz[i]);
mw.visitTypeInsn(NEW, pType); //S3=property
mw.visitInsn(DUP); //S4=Property
mw.visitMethodInsn(INVOKESPECIAL, pType, "<init>", "()V"); //S3=Property
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");//S1 S2,S3消耗 S1=return
mw.visitInsn(POP);//S1移除,留下S0
}
mw.visitInsn(RETURN);
mw.visitMaxs(4, 2);
mw.visitEnd();
}
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getProperties", "()"+getDesc(Collection.class), null,null);
mw.visitVarInsn(ALOAD, 0);
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;");
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "values", "()Ljava/util/Set;");
mw.visitInsn(ARETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
}
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getProperty", ASMUtils.getMethodDesc(jef.tools.reflect.Property.class, String.class), null,null);
mw.visitVarInsn(ALOAD, 0);
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;");
mw.visitVarInsn(ALOAD, 1);
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
mw.visitInsn(ARETURN);
mw.visitMaxs(2,2);
mw.visitEnd();
}
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getAnnotationOnField", getMethodDesc(java.util.Map.class, String.class),null, null);
mw.visitVarInsn(ALOAD, 0); //S1
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 1); //S2
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); //S1
mw.visitInsn(DUP); //S2
Label ifnull=new Label();
mw.visitJumpInsn(IFNULL, ifnull);
mw.visitTypeInsn(CHECKCAST, getType(AbstractFastProperty.class));
mw.visitVarInsn(ASTORE, 2); //S0
mw.visitVarInsn(ALOAD, 0); //S1`
mw.visitFieldInsn(GETFIELD, accessorType, "fieldAnnoMaps", "[Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 2); //S2
mw.visitFieldInsn(GETFIELD, getType(jef.accelerator.bean.AbstractFastProperty.class), "n", "I"); //S2==int
mw.visitInsn(AALOAD);
mw.visitInsn(ARETURN);
mw.visitLabel(ifnull);
mw.visitInsn(POP); //S0
mw.visitTypeInsn(NEW, getType(NoSuchElementException.class));
mw.visitInsn(DUP); //S2
mw.visitTypeInsn(NEW, getType(StringBuilder.class)); //S3
mw.visitInsn(DUP); //S4
mw.visitVarInsn(ALOAD, 1); //S5
mw.visitMethodInsn(INVOKESPECIAL, getType(StringBuilder.class), "<init>",getMethodDesc(Void.TYPE, String.class)); //S3=StringBuilder;
mw.visitLdcInsn(" is not exist in " + beanClass.getName()); //S4 String
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class),"append", getMethodDesc(StringBuilder.class, String.class)); //S3=StringBuilder;
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class), "toString", getMethodDesc(String.class)); //S3=String
mw.visitMethodInsn(INVOKESPECIAL, getType(NoSuchElementException.class),"<init>", getMethodDesc(Void.TYPE, String.class)); //S1=NoSuchElementException
mw.visitInsn(ATHROW);
mw.visitMaxs(5, 3);
mw.visitEnd();
}
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getAnnotationOnGetter", getMethodDesc(java.util.Map.class, String.class),null, null);
mw.visitVarInsn(ALOAD, 0); //S1
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 1); //S2
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); //S1
mw.visitInsn(DUP); //S2
Label ifnull=new Label();
mw.visitJumpInsn(IFNULL, ifnull);//S1
mw.visitTypeInsn(CHECKCAST, getType(AbstractFastProperty.class));
mw.visitVarInsn(ASTORE, 2); //S0
mw.visitVarInsn(ALOAD, 0); //S1
mw.visitFieldInsn(GETFIELD, accessorType, "getterAnnoMaps", "[Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 2); //S2
mw.visitFieldInsn(GETFIELD, getType(jef.accelerator.bean.AbstractFastProperty.class), "n", "I"); //S2==int
mw.visitInsn(AALOAD);
mw.visitInsn(ARETURN);
mw.visitLabel(ifnull);
mw.visitInsn(POP); //S0
mw.visitTypeInsn(NEW, getType(NoSuchElementException.class));
mw.visitInsn(DUP); //S2
mw.visitTypeInsn(NEW, getType(StringBuilder.class)); //S3
mw.visitInsn(DUP); //S4
mw.visitVarInsn(ALOAD, 1); //S5
mw.visitMethodInsn(INVOKESPECIAL, getType(StringBuilder.class), "<init>",getMethodDesc(Void.TYPE, String.class)); //S3=StringBuilder;
mw.visitLdcInsn(" is not exist in " + beanClass.getName()); //S4 String
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class),"append", getMethodDesc(StringBuilder.class, String.class)); //S3=StringBuilder;
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class), "toString", getMethodDesc(String.class)); //S3=String
mw.visitMethodInsn(INVOKESPECIAL, getType(NoSuchElementException.class),"<init>", getMethodDesc(Void.TYPE, String.class)); //S1=NoSuchElementException
mw.visitInsn(ATHROW);
mw.visitMaxs(5, 3);
mw.visitEnd();
}
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getAnnotationOnSetter", getMethodDesc(java.util.Map.class, String.class),null, null);
mw.visitVarInsn(ALOAD, 0); //S1
mw.visitFieldInsn(GETFIELD, accessorType, "fields", "Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 1); //S2
mw.visitMethodInsn(INVOKEINTERFACE, mapType, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); //S1
mw.visitInsn(DUP); //S2 AbstractFastProperty
Label ifnull=new Label();
mw.visitJumpInsn(IFNULL, ifnull); //S1 //如果属性不存在,返回null
mw.visitTypeInsn(CHECKCAST, getType(AbstractFastProperty.class));
mw.visitVarInsn(ASTORE, 2); //S0
mw.visitVarInsn(ALOAD, 0); //S1 this
mw.visitFieldInsn(GETFIELD, accessorType, "setterAnnoMaps", "[Ljava/util/Map;"); //S1
mw.visitVarInsn(ALOAD, 2); //S2 AbstractFastProperty
mw.visitFieldInsn(GETFIELD, getType(jef.accelerator.bean.AbstractFastProperty.class), "n", "I"); //S2==int 获取序号
mw.visitInsn(AALOAD); //setterAnnoMaps是数组,按序号获取
mw.visitInsn(ARETURN);
mw.visitLabel(ifnull);
mw.visitInsn(POP); //S0
mw.visitTypeInsn(NEW, getType(NoSuchElementException.class));
mw.visitInsn(DUP); //S2
mw.visitTypeInsn(NEW, getType(StringBuilder.class)); //S3
mw.visitInsn(DUP); //S4
mw.visitVarInsn(ALOAD, 1); //S5
mw.visitMethodInsn(INVOKESPECIAL, getType(StringBuilder.class), "<init>",getMethodDesc(Void.TYPE, String.class)); //S3=StringBuilder;
mw.visitLdcInsn(" is not exist in " + beanClass.getName()); //S4 String
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class),"append", getMethodDesc(StringBuilder.class, String.class)); //S3=StringBuilder;
mw.visitMethodInsn(INVOKEVIRTUAL, getType(StringBuilder.class), "toString", getMethodDesc(String.class)); //S3=String
mw.visitMethodInsn(INVOKESPECIAL, getType(NoSuchElementException.class),"<init>", getMethodDesc(Void.TYPE, String.class)); //S1=NoSuchElementException
mw.visitInsn(ATHROW);
mw.visitMaxs(5, 3);
mw.visitEnd();
}
super.generatePublicMethods(cw);
cw.visitEnd();
return cw.toByteArray();
}
private void generatePropertyClz() {
for (int i = 0; i < fields.length; i++) {
FieldInfo fi=fields[i];
String pname = this.accessorName + "$" + fi.getName();
byte[] data=generateProperty(i, fi,pname);
//DEBUG
// ASMAccessorFactory.saveClass(data, pname);
Class<?> clz= UnsafeUtils.defineClass(pname, data, 0, data.length, cl);
this.properTyClz[i]=clz;
}
}
private byte[] generateProperty(int i, FieldInfo fi,String pname) {
ClassWriter cw = new ClassWriter(0);
String parentClz = getType(AbstractFastProperty.class);
cw.visit(V1_5, ACC_PUBLIC + ACC_FINAL, pname,null, parentClz, new String[] {});
// //构造器
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,null);
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, parentClz, "<init>", "()V");
mw.visitInsn(RETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
}
// getName
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null,null);
mw.visitLdcInsn(fi.getName());
mw.visitInsn(ARETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
}
// SET
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", null,null);
mw.visitIntInsn(ALOAD,1);//S1
mw.visitTypeInsn(CHECKCAST, beanType);
mw.visitIntInsn(ASTORE,3);//S0
mw.visitIntInsn(ALOAD,3);
mw.visitIntInsn(ALOAD,2); //S2
if(fi.isPrimitive()){
Class<?> wrpped=BeanUtils.toWrapperClass(fi.getRawType());
mw.visitTypeInsn(CHECKCAST, getType(wrpped)); //S2
ASMUtils.doUnwrap(mw, fi.getRawType(), wrpped); //S2
}else{
mw.visitTypeInsn(CHECKCAST, getType(fi.getRawType())); //S2
}
this.generateInvokeMethod(mw, fi.getSetter());
mw.visitInsn(RETURN);
if(fi.isPrimitive()){
mw.visitMaxs(3, 4);
}else{
mw.visitMaxs(2, 4);
}
mw.visitEnd();
}
//GET
{
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null,null);
mw.visitIntInsn(ALOAD,1);
mw.visitTypeInsn(CHECKCAST, beanType);
mw.visitIntInsn(ASTORE,2);
mw.visitIntInsn(ALOAD,0);
mw.visitIntInsn(ALOAD,2);
generateInvokeMethod(mw, fi.getGetter());
if(fi.isPrimitive()){//inbox
ASMUtils.doWrap(mw, fi.getRawType());
}
mw.visitInsn(ARETURN);
mw.visitMaxs(3, 3);
mw.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}