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}