001package io.ebean.enhance.querybean;
002
003import io.ebean.enhance.asm.ClassVisitor;
004import io.ebean.enhance.asm.Label;
005import io.ebean.enhance.asm.MethodVisitor;
006import io.ebean.enhance.asm.Opcodes;
007import io.ebean.enhance.asm.Type;
008
009import static io.ebean.enhance.common.EnhanceConstants.INIT;
010
011/**
012 * Field information.
013 */
014public class FieldInfo implements Opcodes, Constants {
015
016  private final ClassInfo classInfo;
017  private final String name;
018  private final String desc;
019  private final String internalName;
020  private final String signature;
021
022  public FieldInfo(ClassInfo classInfo, String name, String desc, String signature) {
023    this.classInfo = classInfo;
024    this.name = name;
025    this.desc = desc;
026    this.internalName = Type.getType(desc).getInternalName();
027    this.signature = signature;
028  }
029
030  @Override
031  public String toString() {
032    return "name:" + name + " desc:" + desc + " sig:" + signature;
033  }
034
035  /**
036  * Add the 'property access method' that callers should use (instead of get field).
037  */
038  public void writeMethod(ClassVisitor cw, boolean typeQueryRootBean) {
039
040    // simple why to determine the property is an associated bean type
041    boolean assocProperty = desc.contains("/QAssoc");
042
043    if (classInfo.isLog(4)) {
044      classInfo.log(" ... add method _" + name + " assocProperty:" + assocProperty + " rootBean:" + typeQueryRootBean);
045    }
046
047    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "_"+name, "()"+desc, "()"+signature, null);
048    mv.visitCode();
049    Label l0 = new Label();
050    mv.visitLabel(l0);
051    mv.visitLineNumber(1, l0);
052    mv.visitVarInsn(ALOAD, 0);
053    mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), name, desc);
054    Label l1 = new Label();
055    mv.visitJumpInsn(IFNONNULL, l1);
056    Label l2 = new Label();
057    mv.visitLabel(l2);
058    mv.visitLineNumber(2, l2);
059    mv.visitVarInsn(ALOAD, 0);
060    mv.visitTypeInsn(NEW, internalName);
061    mv.visitInsn(DUP);
062    mv.visitLdcInsn(name);
063    mv.visitVarInsn(ALOAD, 0);
064
065    if (assocProperty) {
066      if (typeQueryRootBean) {
067        mv.visitInsn(ICONST_1);
068        mv.visitMethodInsn(INVOKESPECIAL, internalName, INIT, "(Ljava/lang/String;Ljava/lang/Object;I)V", false);
069      } else {
070        mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), FIELD_ROOT, "Ljava/lang/Object;");
071        mv.visitVarInsn(ALOAD, 0);
072        mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), FIELD_PATH, "Ljava/lang/String;");
073        mv.visitInsn(ICONST_1);
074        mv.visitMethodInsn(INVOKESPECIAL, internalName, INIT, "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;I)V", false);
075      }
076
077    } else {
078      if (typeQueryRootBean) {
079        mv.visitMethodInsn(INVOKESPECIAL, internalName, INIT, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
080      } else {
081        mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), FIELD_ROOT, "Ljava/lang/Object;");
082        mv.visitVarInsn(ALOAD, 0);
083        mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), FIELD_PATH, "Ljava/lang/String;");
084        mv.visitMethodInsn(INVOKESPECIAL, internalName, INIT, "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)V", false);
085      }
086    }
087
088    mv.visitFieldInsn(PUTFIELD, classInfo.getClassName(), name, desc);
089    mv.visitLabel(l1);
090    mv.visitLineNumber(3, l1);
091    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
092    mv.visitVarInsn(ALOAD, 0);
093    mv.visitFieldInsn(GETFIELD, classInfo.getClassName(), name, desc);
094    mv.visitInsn(ARETURN);
095    Label l3 = new Label();
096    mv.visitLabel(l3);
097    mv.visitLocalVariable("this", "L" + classInfo.getClassName() + ";", null, l0, l3, 0);
098    if (assocProperty) {
099      if (typeQueryRootBean) {
100        mv.visitMaxs(6, 1);
101      } else {
102        mv.visitMaxs(7, 1);
103      }
104    } else {
105      if (typeQueryRootBean) {
106        mv.visitMaxs(5, 1);
107      } else {
108        mv.visitMaxs(6, 1);
109      }
110    }
111    mv.visitEnd();
112  }
113
114  /**
115  * Initialise the field (used by 'Alias' constructor).
116  */
117  public void writeFieldInit(MethodVisitor mv) {
118    Label l10 = new Label();
119    mv.visitLabel(l10);
120    mv.visitLineNumber(3, l10);
121    mv.visitVarInsn(ALOAD, 0);
122    mv.visitTypeInsn(NEW, internalName);
123    mv.visitInsn(DUP);
124    mv.visitLdcInsn(name);
125    mv.visitVarInsn(ALOAD, 0);
126    mv.visitMethodInsn(INVOKESPECIAL, internalName, INIT, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
127    mv.visitFieldInsn(PUTFIELD, classInfo.getClassName(), name, desc);
128  }
129}