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