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}