001package io.ebean.enhance.querybean; 002 003import io.ebean.enhance.common.EnhanceContext; 004import io.ebean.enhance.common.NoEnhancementRequiredException; 005import io.ebean.enhance.asm.ClassVisitor; 006import io.ebean.enhance.asm.Opcodes; 007 008import java.util.ArrayList; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Set; 012 013/** 014 * Holds meta information for a class. 015 */ 016public class ClassInfo implements Constants { 017 018 /** 019 * Detect entity beans as we will ignore them for this enhancement. 020 */ 021 static Set<String> entityBeanAnnotations = new HashSet<>(); 022 static { 023 entityBeanAnnotations.add(ENTITY_ANNOTATION); 024 entityBeanAnnotations.add(EMBEDDABLE_ANNOTATION); 025 entityBeanAnnotations.add(MAPPEDSUPERCLASS_ANNOTATION); 026 } 027 028 029 private final EnhanceContext enhanceContext; 030 031 private final String className; 032 033 private boolean addedMarkerAnnotation; 034 035 private boolean typeQueryBean; 036 037 private boolean typeQueryUser; 038 039 private boolean alreadyEnhanced; 040 041 private List<FieldInfo> fields; 042 043 private boolean hasBasicConstructor; 044 045 private boolean hasMainConstructor; 046 047 public ClassInfo(EnhanceContext enhanceContext, String className) { 048 this.enhanceContext = enhanceContext; 049 this.className = className; 050 } 051 052 /** 053 * Return the className. 054 */ 055 public String getClassName() { 056 return className; 057 } 058 059 /** 060 * Return true if the bean is already enhanced. 061 */ 062 public boolean isAlreadyEnhanced() { 063 return alreadyEnhanced; 064 } 065 066 public boolean addMarkerAnnotation() { 067 if (addedMarkerAnnotation) { 068 return false; 069 } 070 addedMarkerAnnotation = true; 071 return true; 072 } 073 074 /** 075 * Return true if the bean is a type query bean. 076 */ 077 public boolean isTypeQueryBean() { 078 return typeQueryBean; 079 } 080 081 /** 082 * Return true if the class is explicitly annotated with TypeQueryUser annotation. 083 */ 084 public boolean isTypeQueryUser() { 085 return typeQueryUser; 086 } 087 088 /** 089 * Check for the type query bean and type query user annotations. 090 */ 091 public void checkTypeQueryAnnotation(String desc) { 092 if (isTypeQueryBeanAnnotation(desc)) { 093 typeQueryBean = true; 094 } else if (isAlreadyEnhancedAnnotation(desc)) { 095 alreadyEnhanced = true; 096 } 097 } 098 099 /** 100 * Add the type query bean field. We will create a 'property access' method for each field. 101 */ 102 public void addField(int access, String name, String desc, String signature) { 103 104 if (((access & Opcodes.ACC_PUBLIC) != 0)) { 105 if (fields == null) { 106 fields = new ArrayList<>(); 107 } 108 if ((access & Opcodes.ACC_STATIC) == 0) { 109 fields.add(new FieldInfo(this, name, desc, signature)); 110 } 111 } 112 } 113 114 /** 115 * Return true if the annotation is the TypeQueryBean annotation. 116 */ 117 private boolean isAlreadyEnhancedAnnotation(String desc) { 118 return ANNOTATION_ALREADY_ENHANCED_MARKER.equals(desc); 119 } 120 121 /** 122 * Return true if the annotation is the TypeQueryBean annotation. 123 */ 124 private boolean isTypeQueryBeanAnnotation(String desc) { 125 return ANNOTATION_TYPE_QUERY_BEAN.equals(desc); 126 } 127 128 /** 129 * Return true if this is one of the entity bean annotations. 130 */ 131 private boolean isEntityBeanAnnotation(String desc) { 132 return entityBeanAnnotations.contains(desc); 133 } 134 135 /** 136 * Return the fields for a type query bean. 137 */ 138 public List<FieldInfo> getFields() { 139 return fields; 140 } 141 142 /** 143 * Note that a GETFIELD call has been replaced to method call. 144 */ 145 public void addGetFieldIntercept(String owner, String name) { 146 147 if (isLog(4)) { 148 log("change getfield " + owner + " name:" + name); 149 } 150 typeQueryUser = true; 151 } 152 153 public boolean isLog(int level) { 154 return enhanceContext.isLog(level); 155 } 156 157 public void log(String msg) { 158 enhanceContext.log(className, msg); 159 } 160 161 /** 162 * There is a basic constructor on the assoc bean which is being overwritten (so don't need to add later). 163 */ 164 public void setHasBasicConstructor() { 165 if (isLog(3)) { 166 log("replace assoc bean basic constructor"); 167 } 168 hasBasicConstructor = true; 169 } 170 171 /** 172 * There is a main constructor on the assoc bean which is being overwritten (so don't need to add later). 173 */ 174 public void setHasMainConstructor() { 175 if (isLog(3)) { 176 log("replace assoc bean main constructor"); 177 } 178 hasMainConstructor = true; 179 } 180 181 /** 182 * Add fields and constructors to assoc type query beans as necessary. 183 */ 184 public void addAssocBeanExtras(ClassVisitor cv) { 185 186 if (isLog(3)) { 187 String msg = "... add fields"; 188 if (!hasBasicConstructor) { 189 msg += ", basic constructor"; 190 } 191 if (!hasMainConstructor) { 192 msg += ", main constructor"; 193 } 194 log(msg); 195 } 196 197 if (!hasBasicConstructor) { 198 // add the assoc bean basic constructor 199 new TypeQueryAssocBasicConstructor(this, cv, ASSOC_BEAN_BASIC_CONSTRUCTOR_DESC, ASSOC_BEAN_BASIC_SIG).visitCode(); 200 } 201 if (!hasMainConstructor) { 202 // add the assoc bean main constructor 203 new TypeQueryAssocMainConstructor(this, cv, ASSOC_BEAN_MAIN_CONSTRUCTOR_DESC, ASSOC_BEAN_MAIN_SIG).visitCode(); 204 } 205 206 } 207 208}