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