1 19 20 package org.apache.cayenne.jpa.conf; 21 22 import java.lang.annotation.Annotation ; 23 import java.lang.reflect.AnnotatedElement ; 24 import java.lang.reflect.Method ; 25 import java.lang.reflect.Modifier ; 26 import java.util.ArrayList ; 27 import java.util.Arrays ; 28 import java.util.Collection ; 29 import java.util.Comparator ; 30 import java.util.HashMap ; 31 import java.util.LinkedList ; 32 import java.util.Map ; 33 34 import javax.persistence.AssociationOverride; 35 import javax.persistence.AssociationOverrides; 36 import javax.persistence.AttributeOverride; 37 import javax.persistence.AttributeOverrides; 38 import javax.persistence.Basic; 39 import javax.persistence.Column; 40 import javax.persistence.Embeddable; 41 import javax.persistence.Embedded; 42 import javax.persistence.EmbeddedId; 43 import javax.persistence.Entity; 44 import javax.persistence.EntityListeners; 45 import javax.persistence.Enumerated; 46 import javax.persistence.GeneratedValue; 47 import javax.persistence.Id; 48 import javax.persistence.Lob; 49 import javax.persistence.ManyToMany; 50 import javax.persistence.ManyToOne; 51 import javax.persistence.MapKey; 52 import javax.persistence.MappedSuperclass; 53 import javax.persistence.NamedNativeQueries; 54 import javax.persistence.NamedNativeQuery; 55 import javax.persistence.NamedQueries; 56 import javax.persistence.NamedQuery; 57 import javax.persistence.OneToMany; 58 import javax.persistence.OneToOne; 59 import javax.persistence.OrderBy; 60 import javax.persistence.SequenceGenerator; 61 import javax.persistence.SqlResultSetMapping; 62 import javax.persistence.TableGenerator; 63 import javax.persistence.Temporal; 64 import javax.persistence.Transient; 65 import javax.persistence.Version; 66 67 import org.apache.cayenne.jpa.JpaProviderException; 68 import org.apache.cayenne.jpa.map.AccessType; 69 import org.apache.cayenne.jpa.map.JpaAbstractEntity; 70 import org.apache.cayenne.jpa.map.JpaAttribute; 71 import org.apache.cayenne.jpa.map.JpaClassDescriptor; 72 import org.apache.cayenne.jpa.map.JpaManagedClass; 73 import org.apache.cayenne.jpa.map.JpaPropertyDescriptor; 74 import org.apache.cayenne.util.Util; 75 import org.apache.cayenne.validation.SimpleValidationFailure; 76 77 87 public class EntityMapAnnotationLoader { 88 89 static final Map <String , Integer > TYPE_ANNOTATION_ORDERING_WEIGHTS; 90 static final Map <String , Integer > MEMBER_ANNOTATION_ORDERING_WEIGHTS; 91 92 static { 93 94 TYPE_ANNOTATION_ORDERING_WEIGHTS = new HashMap <String , Integer >(); 95 96 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(Entity.class.getName(), 1); 98 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(Embeddable.class.getName(), 1); 99 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(MappedSuperclass.class.getName(), 1); 100 101 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(SequenceGenerator.class.getName(), 2); 103 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(NamedNativeQueries.class.getName(), 2); 104 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(NamedNativeQuery.class.getName(), 2); 105 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(NamedQueries.class.getName(), 2); 106 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(NamedQuery.class.getName(), 2); 107 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(SqlResultSetMapping.class.getName(), 2); 108 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(TableGenerator.class.getName(), 2); 109 TYPE_ANNOTATION_ORDERING_WEIGHTS.put(EntityListeners.class.getName(), 2); 110 111 MEMBER_ANNOTATION_ORDERING_WEIGHTS = new HashMap <String , Integer >(); 112 113 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Id.class.getName(), 1); 116 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Basic.class.getName(), 1); 117 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(EmbeddedId.class.getName(), 1); 118 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Version.class.getName(), 1); 119 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(ManyToOne.class.getName(), 1); 120 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(OneToMany.class.getName(), 1); 121 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(OneToOne.class.getName(), 1); 122 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(ManyToMany.class.getName(), 1); 123 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Embedded.class.getName(), 1); 124 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Transient.class.getName(), 1); 125 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(AssociationOverride.class.getName(), 1); 126 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(AssociationOverrides.class.getName(), 1); 127 128 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(AttributeOverride.class.getName(), 2); 131 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(AttributeOverrides.class.getName(), 2); 132 133 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(GeneratedValue.class.getName(), 3); 136 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Temporal.class.getName(), 3); 137 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(TableGenerator.class.getName(), 3); 138 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(SequenceGenerator.class.getName(), 3); 139 140 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Lob.class.getName(), 3); 141 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Temporal.class.getName(), 3); 142 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Enumerated.class.getName(), 3); 143 144 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(MapKey.class.getName(), 3); 145 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(OrderBy.class.getName(), 3); 146 MEMBER_ANNOTATION_ORDERING_WEIGHTS.put(Column.class.getName(), 3); 147 } 148 149 protected EntityMapLoaderContext context; 150 151 protected Comparator <Annotation > typeAnnotationsSorter; 152 protected Comparator <Annotation > memberAnnotationsSorter; 153 154 protected AnnotationProcessorFactory classProcessorFactory; 155 protected AnnotationProcessorFactory memberProcessorFactory; 156 protected AnnotationProcessorFactory callbackProcessorFactory; 157 158 public EntityMapAnnotationLoader(EntityMapLoaderContext context) { 159 this.context = context; 160 this.typeAnnotationsSorter = new AnnotationSorter( 161 TYPE_ANNOTATION_ORDERING_WEIGHTS); 162 this.memberAnnotationsSorter = new AnnotationSorter( 163 MEMBER_ANNOTATION_ORDERING_WEIGHTS); 164 165 this.classProcessorFactory = new ClassAnnotationProcessorFactory(); 166 this.memberProcessorFactory = new MemberAnnotationProcessorFactory(); 167 this.callbackProcessorFactory = new EntityCallbackAnnotationProcessorFactory(); 168 } 169 170 174 public void loadClassMapping(Class managedClass) throws JpaProviderException { 175 176 if (context.getEntityMap().containsManagedClass(managedClass.getName())) { 178 context.recordConflict(new SimpleValidationFailure( 179 managedClass.getName(), 180 "Duplicate managed class declaration " + managedClass.getName())); 181 return; 182 } 183 184 Annotation [] classAnnotations = managedClass.getAnnotations(); 185 186 Arrays.sort(classAnnotations, typeAnnotationsSorter); 188 189 JpaClassDescriptor descriptor = new JpaClassDescriptor(managedClass); 190 191 descriptor.setAccess(context.getEntityMap().getAccess()); 193 194 AnnotationContext stack = new AnnotationContext(descriptor); 195 stack.push(context.getEntityMap()); 196 197 for (int i = 0; i < classAnnotations.length; i++) { 199 AnnotationProcessor processor = classProcessorFactory 200 .getProcessor(classAnnotations[i]); 201 if (processor != null) { 202 processor.onStartElement(managedClass, stack); 203 } 204 } 205 206 if (stack.depth() == 1) { 208 return; 209 } 210 211 if (stack.peek() instanceof JpaAbstractEntity) { 213 for (Method callback : getEntityCallbacks(managedClass)) { 214 applyEntityCallbackAnnotations(callback, stack); 215 } 216 } 217 218 220 224 228 boolean fieldAccess = false; 229 230 for (JpaPropertyDescriptor property : descriptor.getFieldDescriptors()) { 231 stack.setPropertyDescriptor(property); 232 if (applyMemberAnnotations(property, stack)) { 233 fieldAccess = true; 234 } 235 } 236 237 boolean propertyAccess = false; 238 239 for (JpaPropertyDescriptor property : descriptor.getPropertyDescriptors()) { 240 stack.setPropertyDescriptor(property); 241 if (applyMemberAnnotations(property, stack)) { 242 propertyAccess = true; 243 } 244 } 245 246 if (stack.peek() instanceof JpaManagedClass) { 247 JpaManagedClass entity = (JpaManagedClass) stack.peek(); 248 if (fieldAccess && propertyAccess) { 250 throw new JpaProviderException("Entity '" 251 + entity.getClassName() 252 + "' has both property and field annotations."); 253 } 254 255 if (fieldAccess) { 258 descriptor.setAccess(AccessType.FIELD); 259 entity.setAccess(AccessType.FIELD); 260 } 261 else if (propertyAccess) { 262 descriptor.setAccess(AccessType.PROPERTY); 263 entity.setAccess(AccessType.PROPERTY); 264 } 265 } 266 267 for (int i = classAnnotations.length - 1; i >= 0; i--) { 269 AnnotationProcessor processor = classProcessorFactory 270 .getProcessor(classAnnotations[i]); 271 if (processor != null) { 272 processor.onFinishElement(managedClass, stack); 273 } 274 } 275 } 276 277 281 protected boolean applyMemberAnnotations( 282 JpaPropertyDescriptor property, 283 AnnotationProcessorStack stack) { 284 285 AnnotatedElement member = property.getMember(); 286 287 Annotation [] annotations = member.getAnnotations(); 288 Arrays.sort(annotations, memberAnnotationsSorter); 290 291 for (int j = 0; j < annotations.length; j++) { 292 293 AnnotationProcessor memberProcessor = memberProcessorFactory 294 .getProcessor(annotations[j]); 295 296 if (memberProcessor != null) { 297 memberProcessor.onStartElement(member, stack); 298 } 299 } 300 301 for (int j = annotations.length - 1; j >= 0; j--) { 302 303 AnnotationProcessor memberProcessor = memberProcessorFactory 304 .getProcessor(annotations[j]); 305 306 if (memberProcessor != null) { 307 memberProcessor.onFinishElement(member, stack); 308 } 309 } 310 311 return annotations.length > 0; 312 } 313 314 protected void applyEntityCallbackAnnotations( 315 Method method, 316 AnnotationProcessorStack stack) { 317 318 Annotation [] annotations = method.getAnnotations(); 319 320 for (int j = 0; j < annotations.length; j++) { 321 322 AnnotationProcessor callbackProcessor = callbackProcessorFactory 323 .getProcessor(annotations[j]); 324 325 if (callbackProcessor != null) { 326 callbackProcessor.onStartElement(method, stack); 327 } 328 } 329 330 } 333 334 338 protected Collection <Method > getEntityCallbacks(Class managedClass) { 339 340 Collection <Method > callbacks = new ArrayList <Method >(3); 341 342 Method [] methods = managedClass.getDeclaredMethods(); 343 for (int i = 0; i < methods.length; i++) { 344 345 int modifiers = methods[i].getModifiers(); 346 if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { 347 continue; 348 } 349 350 if (!Void.TYPE.equals(methods[i].getReturnType())) { 351 continue; 352 } 353 354 Class [] params = methods[i].getParameterTypes(); 355 if (params.length != 0) { 356 continue; 357 } 358 359 callbacks.add(methods[i]); 360 } 361 362 return callbacks; 363 } 364 365 369 final class AnnotationSorter implements Comparator <Annotation > { 370 371 private Map <String , Integer > weights; 372 373 AnnotationSorter(Map <String , Integer > weights) { 374 this.weights = weights; 375 } 376 377 public int compare(Annotation o1, Annotation o2) { 378 Integer w1 = weights.get(o1.annotationType().getName()); 379 Integer w2 = weights.get(o2.annotationType().getName()); 380 381 return Util.nullSafeCompare(false, w1, w2); 384 } 385 } 386 387 final class AnnotationContext implements AnnotationProcessorStack { 388 389 LinkedList stack = new LinkedList (); 390 JpaClassDescriptor classDescriptor; 391 JpaPropertyDescriptor propertyDescriptor; 392 393 AnnotationContext(JpaClassDescriptor classDescriptor) { 394 this.classDescriptor = classDescriptor; 395 } 396 397 void setPropertyDescriptor(JpaPropertyDescriptor propertyDescriptor) { 398 this.propertyDescriptor = propertyDescriptor; 399 } 400 401 public int depth() { 402 return stack.size(); 403 } 404 405 public Object peek() { 406 return stack.peek(); 407 } 408 409 public Object pop() { 410 return stack.removeFirst(); 411 } 412 413 public void push(Object object) { 414 415 if (object instanceof JpaAttribute) { 417 JpaAttribute attribute = (JpaAttribute) object; 418 attribute.setName(propertyDescriptor.getName()); 419 attribute.setPropertyDescriptor(propertyDescriptor); 420 } 421 else if (object instanceof JpaManagedClass) { 422 ((JpaManagedClass) object).setClassDescriptor(classDescriptor); 423 } 424 425 stack.addFirst(object); 426 } 427 428 public void recordConflict( 429 AnnotatedElement element, 430 Class annotatedType, 431 String message) { 432 433 StringBuilder buffer = new StringBuilder (); 434 buffer.append("Problem processing annotation: ").append( 435 annotatedType.getName()); 436 buffer.append(", annotated element: ").append(element); 437 438 if (message != null) { 439 buffer.append(", details: ").append(message); 440 } 441 442 context 443 .recordConflict(new SimpleValidationFailure(peek(), buffer.toString())); 444 } 445 } 446 } 447 | Popular Tags |