mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
ENH: meta-annotation support similar to spring.
See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-meta-annotations for detailed explanation
This commit is contained in:
+2
-8
@@ -5,6 +5,7 @@ import com.avaje.ebean.annotation.ChangeLogInsertMode;
|
||||
import com.avaje.ebean.event.BeanPersistRequest;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogFilter;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.AnnotationBase;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -52,14 +53,7 @@ public class DefaultChangeLogRegister implements ChangeLogRegister {
|
||||
* Find and return the ChangeLog annotation in the inheritance hierarchy.
|
||||
*/
|
||||
private ChangeLog getChangeLog(Class<?> beanType) {
|
||||
ChangeLog changeLog = beanType.getAnnotation(ChangeLog.class);
|
||||
if (changeLog != null) {
|
||||
return changeLog;
|
||||
}
|
||||
if (Object.class.equals(beanType.getSuperclass())) {
|
||||
return null;
|
||||
}
|
||||
return getChangeLog(beanType.getSuperclass());
|
||||
return AnnotationBase.findAnnotation(beanType, ChangeLog.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.AnnotationBase;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
@@ -1457,7 +1458,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* If so it is ok for it not to be enhanced.
|
||||
*/
|
||||
private boolean isMappedSuperWithNoProperties(Class<?> beanClass) {
|
||||
|
||||
// Attention: do not use AnnotationBase.findAnnotation(cls,...) here.
|
||||
MappedSuperclass annotation = beanClass.getAnnotation(MappedSuperclass.class);
|
||||
if (annotation == null) {
|
||||
return false;
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployDocPropertyOptions;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.AnnotationBase;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyGetter;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
@@ -233,29 +234,29 @@ public class DeployBeanProperty {
|
||||
if (field == null) {
|
||||
return 0;
|
||||
}
|
||||
if (field.getAnnotation(Id.class) != null) {
|
||||
if (AnnotationBase.findAnnotation(field, Id.class) != null) {
|
||||
return ID_ORDER;
|
||||
} else if (field.getAnnotation(EmbeddedId.class) != null) {
|
||||
} else if (AnnotationBase.findAnnotation(field, EmbeddedId.class) != null) {
|
||||
return ID_ORDER;
|
||||
} else if (undirectionalShadow) {
|
||||
return UNIDIRECTIONAL_ORDER;
|
||||
} else if (isAuditProperty()) {
|
||||
return AUDITCOLUMN_ORDER;
|
||||
} else if (field.getAnnotation(Version.class) != null) {
|
||||
} else if (AnnotationBase.findAnnotation(field, Version.class) != null) {
|
||||
return VERSIONCOLUMN_ORDER;
|
||||
} else if (field.getAnnotation(SoftDelete.class) != null) {
|
||||
} else if (AnnotationBase.findAnnotation(field, SoftDelete.class) != null) {
|
||||
return VERSIONCOLUMN_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean isAuditProperty() {
|
||||
return (field.getAnnotation(WhenCreated.class) != null
|
||||
|| field.getAnnotation(WhenModified.class) != null
|
||||
|| field.getAnnotation(WhoModified.class) != null
|
||||
|| field.getAnnotation(WhoCreated.class) != null
|
||||
|| field.getAnnotation(UpdatedTimestamp.class) != null
|
||||
|| field.getAnnotation(CreatedTimestamp.class) != null);
|
||||
return (AnnotationBase.findAnnotation(field, WhenCreated.class) != null
|
||||
|| AnnotationBase.findAnnotation(field, WhenModified.class) != null
|
||||
|| AnnotationBase.findAnnotation(field, WhoModified.class) != null
|
||||
|| AnnotationBase.findAnnotation(field, WhoCreated.class) != null
|
||||
|| AnnotationBase.findAnnotation(field, UpdatedTimestamp.class) != null
|
||||
|| AnnotationBase.findAnnotation(field, CreatedTimestamp.class) != null);
|
||||
}
|
||||
|
||||
public String getFullBeanName() {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -46,12 +49,12 @@ public abstract class AnnotationBase {
|
||||
T a = null;
|
||||
Field field = prop.getField();
|
||||
if (field != null) {
|
||||
a = field.getAnnotation(annClass);
|
||||
a = findAnnotation(field, annClass);
|
||||
}
|
||||
if (a == null) {
|
||||
Method m = prop.getReadMethod();
|
||||
if (m != null) {
|
||||
a = m.getAnnotation(annClass);
|
||||
a = findAnnotation(m, annClass);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
@@ -66,10 +69,95 @@ public abstract class AnnotationBase {
|
||||
protected <T extends Annotation> T find(DeployBeanProperty prop, Class<T> annClass) {
|
||||
T a = get(prop, annClass);
|
||||
if (a == null) {
|
||||
a = prop.getOwningType().getAnnotation(annClass);
|
||||
a = findAnnotation(prop.getOwningType(),annClass);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
// this code is taken from the spring framework to find annotations recursively
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Annotation} is defined in the core JDK
|
||||
* {@code java.lang.annotation} package.
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
|
||||
return annotation.annotationType().getName().startsWith("java.lang.annotation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the
|
||||
* supplied {@link AnnotatedElement}.
|
||||
* <p>Meta-annotations will be searched if the annotation is not
|
||||
* <em>directly present</em> on the supplied element.
|
||||
* <p><strong>Warning</strong>: this method operates generically on
|
||||
* annotated elements. In other words, this method does not execute
|
||||
* specialized search algorithms for classes or methods. It only
|
||||
* traverses through Annotations!</p>
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// check if directly present, if not, start recursive traversal
|
||||
A ann = annotatedElement.getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
} else {
|
||||
return findAnnotation(annotatedElement, annotationType, new HashSet<Annotation>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the
|
||||
* supplied {@link clazz}.
|
||||
* <p>Meta-annotations will be searched if the annotation is not
|
||||
* <em>directly present</em> on the supplied element.
|
||||
* <p><strong>Note</strong>: this method searches for annotations at
|
||||
* class & superClass(es)!</p>
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// check if directly present, if not, start recursive traversal
|
||||
A ann = clazz.getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
} else {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
ann = findAnnotation(clazz, annotationType, new HashSet<Annotation>());
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
// not present at this class - traverse to superclass
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Perform the search algorithm for {@link #findAnnotation(AnnotatedElement, Class)}
|
||||
* avoiding endless recursion by tracking which annotations have already
|
||||
* been <em>visited</em>.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
|
||||
|
||||
Annotation[] anns = annotatedElement.getDeclaredAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
}
|
||||
}
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
A annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class AnnotationClass extends AnnotationParser {
|
||||
public void parseAttributeOverride() {
|
||||
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
AttributeOverride override = cls.getAnnotation(AttributeOverride.class);
|
||||
AttributeOverride override = AnnotationBase.findAnnotation(cls,AttributeOverride.class);
|
||||
if (override != null) {
|
||||
String propertyName = override.name();
|
||||
Column column = override.column();
|
||||
@@ -103,7 +103,7 @@ public class AnnotationClass extends AnnotationParser {
|
||||
|
||||
private void read(Class<?> cls) {
|
||||
|
||||
Entity entity = cls.getAnnotation(Entity.class);
|
||||
Entity entity = AnnotationBase.findAnnotation(cls,Entity.class);
|
||||
if (entity != null) {
|
||||
if (entity.name().equals("")) {
|
||||
descriptor.setName(cls.getSimpleName());
|
||||
@@ -112,27 +112,27 @@ public class AnnotationClass extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
Embeddable embeddable = cls.getAnnotation(Embeddable.class);
|
||||
Embeddable embeddable = AnnotationBase.findAnnotation(cls,Embeddable.class);
|
||||
if (embeddable != null) {
|
||||
descriptor.setEntityType(EntityType.EMBEDDED);
|
||||
descriptor.setName("Embeddable:" + cls.getSimpleName());
|
||||
}
|
||||
|
||||
Index index = cls.getAnnotation(Index.class);
|
||||
Index index = AnnotationBase.findAnnotation(cls,Index.class);
|
||||
if (index != null) {
|
||||
descriptor.addIndex(new IndexDefinition(index.columnNames(), index.name(), index.unique()));
|
||||
}
|
||||
|
||||
UniqueConstraint uc = cls.getAnnotation(UniqueConstraint.class);
|
||||
UniqueConstraint uc = AnnotationBase.findAnnotation(cls,UniqueConstraint.class);
|
||||
if (uc != null) {
|
||||
descriptor.addIndex(new IndexDefinition(uc.columnNames()));
|
||||
}
|
||||
|
||||
View view = cls.getAnnotation(View.class);
|
||||
View view = AnnotationBase.findAnnotation(cls,View.class);
|
||||
if (view != null) {
|
||||
descriptor.setView(view.name(), view.dependentTables());
|
||||
}
|
||||
Table table = cls.getAnnotation(Table.class);
|
||||
Table table = AnnotationBase.findAnnotation(cls,Table.class);
|
||||
if (table != null) {
|
||||
UniqueConstraint[] uniqueConstraints = table.uniqueConstraints();
|
||||
for (UniqueConstraint c : uniqueConstraints) {
|
||||
@@ -140,54 +140,54 @@ public class AnnotationClass extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
Draftable draftable = cls.getAnnotation(Draftable.class);
|
||||
Draftable draftable = AnnotationBase.findAnnotation(cls,Draftable.class);
|
||||
if (draftable != null) {
|
||||
descriptor.setDraftable();
|
||||
}
|
||||
|
||||
DraftableElement draftableElement = cls.getAnnotation(DraftableElement.class);
|
||||
DraftableElement draftableElement = AnnotationBase.findAnnotation(cls,DraftableElement.class);
|
||||
if (draftableElement != null) {
|
||||
descriptor.setDraftableElement();
|
||||
}
|
||||
|
||||
ReadAudit readAudit = cls.getAnnotation(ReadAudit.class);
|
||||
ReadAudit readAudit = AnnotationBase.findAnnotation(cls,ReadAudit.class);
|
||||
if (readAudit != null) {
|
||||
descriptor.setReadAuditing();
|
||||
}
|
||||
|
||||
History history = cls.getAnnotation(History.class);
|
||||
History history = AnnotationBase.findAnnotation(cls,History.class);
|
||||
if (history != null) {
|
||||
descriptor.setHistorySupport();
|
||||
}
|
||||
|
||||
DbComment comment = cls.getAnnotation(DbComment.class);
|
||||
DbComment comment = AnnotationBase.findAnnotation(cls,DbComment.class);
|
||||
if (comment != null) {
|
||||
descriptor.setDbComment(comment.value());
|
||||
}
|
||||
|
||||
DocStore docStore = cls.getAnnotation(DocStore.class);
|
||||
DocStore docStore = AnnotationBase.findAnnotation(cls,DocStore.class);
|
||||
if (docStore != null) {
|
||||
descriptor.readDocStore(docStore);
|
||||
}
|
||||
|
||||
UpdateMode updateMode = cls.getAnnotation(UpdateMode.class);
|
||||
UpdateMode updateMode = AnnotationBase.findAnnotation(cls,UpdateMode.class);
|
||||
if (updateMode != null) {
|
||||
descriptor.setUpdateChangesOnly(updateMode.updateChangesOnly());
|
||||
}
|
||||
|
||||
Cache cache = cls.getAnnotation(Cache.class);
|
||||
Cache cache = AnnotationBase.findAnnotation(cls,Cache.class);
|
||||
if (cache != null && !disableL2Cache) {
|
||||
descriptor.setCache(cache);
|
||||
}
|
||||
|
||||
NamedQueries namedQueries = cls.getAnnotation(NamedQueries.class);
|
||||
NamedQueries namedQueries = AnnotationBase.findAnnotation(cls,NamedQueries.class);
|
||||
if (namedQueries != null) {
|
||||
for (NamedQuery namedQuery : namedQueries.value()) {
|
||||
descriptor.addNamedQuery(namedQuery.name(), namedQuery.query());
|
||||
}
|
||||
}
|
||||
|
||||
NamedQuery namedQuery = cls.getAnnotation(NamedQuery.class);
|
||||
NamedQuery namedQuery = AnnotationBase.findAnnotation(cls,NamedQuery.class);
|
||||
if (namedQuery != null) {
|
||||
descriptor.addNamedQuery(namedQuery.name(), namedQuery.query());
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class AnnotationSql extends AnnotationParser {
|
||||
|
||||
public void parse() {
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
Sql sql = cls.getAnnotation(Sql.class);
|
||||
Sql sql = AnnotationBase.findAnnotation(cls,Sql.class);
|
||||
if (sql != null) {
|
||||
descriptor.setEntityType(BeanDescriptor.EntityType.SQL);
|
||||
}
|
||||
|
||||
+7
-7
@@ -223,7 +223,7 @@ public class DeployCreateProperties {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
|
||||
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
|
||||
ManyToOne manyToOne = AnnotationBase.findAnnotation(field,ManyToOne.class);
|
||||
if (manyToOne != null){
|
||||
Class<?> tt = manyToOne.targetEntity();
|
||||
if (!tt.equals(void.class)){
|
||||
@@ -240,7 +240,7 @@ public class DeployCreateProperties {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
if (targetType == null) {
|
||||
Transient transAnnotation = field.getAnnotation(Transient.class);
|
||||
Transient transAnnotation = AnnotationBase.findAnnotation(field,Transient.class);
|
||||
if (transAnnotation != null) {
|
||||
// not supporting this field (generic type used)
|
||||
return null;
|
||||
@@ -298,15 +298,15 @@ public class DeployCreateProperties {
|
||||
* Return true if the field has one of the special mappings.
|
||||
*/
|
||||
private boolean isSpecialScalarType(Field field) {
|
||||
return (field.getAnnotation(DbJson.class) != null)
|
||||
|| (field.getAnnotation(DbJsonB.class) != null)
|
||||
|| (field.getAnnotation(DbArray.class) != null)
|
||||
|| (field.getAnnotation(DbHstore.class) != null);
|
||||
return (AnnotationBase.findAnnotation(field,DbJson.class) != null)
|
||||
|| (AnnotationBase.findAnnotation(field,DbJsonB.class) != null)
|
||||
|| (AnnotationBase.findAnnotation(field,DbArray.class) != null)
|
||||
|| (AnnotationBase.findAnnotation(field,DbHstore.class) != null);
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
Transient t = field.getAnnotation(Transient.class);
|
||||
Transient t = AnnotationBase.findAnnotation(field,Transient.class);
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@ public class DeployInherit {
|
||||
info.setParent(parent);
|
||||
}
|
||||
|
||||
Inheritance ia = cls.getAnnotation(Inheritance.class);
|
||||
Inheritance ia = AnnotationBase.findAnnotation(cls,Inheritance.class);
|
||||
if (ia != null) {
|
||||
ia.strategy();
|
||||
}
|
||||
DiscriminatorColumn da = cls.getAnnotation(DiscriminatorColumn.class);
|
||||
DiscriminatorColumn da = AnnotationBase.findAnnotation(cls,DiscriminatorColumn.class);
|
||||
if (da != null) {
|
||||
// lowercase the discriminator column for RawSql and JSON
|
||||
info.setDiscriminatorColumn(da.name().toLowerCase());
|
||||
@@ -128,7 +128,7 @@ public class DeployInherit {
|
||||
info.setDiscriminatorLength(da.length());
|
||||
}
|
||||
|
||||
DiscriminatorValue dv = cls.getAnnotation(DiscriminatorValue.class);
|
||||
DiscriminatorValue dv = AnnotationBase.findAnnotation(cls,DiscriminatorValue.class);
|
||||
if (dv != null) {
|
||||
info.setDiscriminatorValue(dv.value());
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public class DeployInherit {
|
||||
if (cls.equals(Object.class)) {
|
||||
return false;
|
||||
}
|
||||
Annotation a = cls.getAnnotation(Inheritance.class);
|
||||
Annotation a = AnnotationBase.findAnnotation(cls,Inheritance.class);
|
||||
if (a != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user