mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Better support for repeatable annotations (needs Java 8)
This commit is contained in:
@@ -241,8 +241,8 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
/**
|
||||
* special validation group for @NotNull annotation to enforce <code>NOT NULL</code> generation on DDL.
|
||||
* Normally if you put the {@link NotNull} annotation on a property, Ebean will only generate a
|
||||
* <code>NOT NULL</code> in DDL if you do not change the validation-groups!
|
||||
*/
|
||||
public interface EbeanDDL {
|
||||
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
@@ -67,6 +69,7 @@ import com.avaje.ebean.Query;
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Formula.List.class)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
@@ -102,5 +105,17 @@ public @interface Formula {
|
||||
* }</pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
Class<? extends DatabasePlatform>[] platforms() default {};
|
||||
|
||||
/**
|
||||
* Repeatable support for {@link Formula}.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface List {
|
||||
|
||||
Formula[] value() default {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
@@ -40,6 +43,7 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Where.List.class)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
@@ -50,5 +54,19 @@ public @interface Where {
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
/**
|
||||
* The platform where this annotation is active. Default: any platform
|
||||
*/
|
||||
Class<? extends DatabasePlatform>[] platforms() default {};
|
||||
|
||||
/**
|
||||
* Repeatable support for {@link Where}.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface List {
|
||||
|
||||
Where[] value() default {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a join to another table during deployment phase.
|
||||
@@ -91,6 +92,15 @@ public class DeployTableJoin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn set.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, Set<JoinColumn> jcSet, BeanTable beanTable) {
|
||||
for (JoinColumn jc: jcSet) {
|
||||
addJoinColumn(order, jc, beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapKey;
|
||||
@@ -87,14 +88,10 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumn, beanTable);
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
Set<JoinColumn> joinColumns = getAll(prop, JoinColumn.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumns.value(), beanTable);
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumns, beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
@@ -93,7 +93,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null) {
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
@@ -102,8 +102,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
JoinColumn joinColumn = get(prop, JoinColumn.class);
|
||||
if (joinColumn != null) {
|
||||
for (JoinColumn joinColumn : getAll(prop, JoinColumn.class)) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
@@ -113,14 +112,18 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
JoinColumns joinColumns = get(prop, JoinColumns.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumns.value(), beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinTable.joinColumns(), beanTable);
|
||||
for (JoinColumn joinColumn : joinTable.joinColumns()) {
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
}
|
||||
if (!joinColumn.nullable()) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.setBeanJoinType(prop, prop.isNullable());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.Formula;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
@@ -9,7 +11,14 @@ import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* Provides some base methods for processing deployment annotations.
|
||||
@@ -38,28 +47,58 @@ public abstract class AnnotationBase {
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
* Looks first at the field and then at the getter method.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a <code>repeatable</code> annotation class is specified and the annotation is platform
|
||||
* specific(see {@link #getPlatformMatchingAnnotation(Set, Class)}), then the platform specific
|
||||
* annotation is returned. Otherwise the first annotation is retured. Note that you must no longer
|
||||
* handle "java 1.6 repeatable containers" like {@link JoinColumn} / {@link JoinColumns} yourself.
|
||||
* </p>
|
||||
* <p>
|
||||
*/
|
||||
protected <T extends Annotation> T get(DeployBeanProperty prop, Class<T> annClass) {
|
||||
T a = null;
|
||||
Field field = prop.getField();
|
||||
if (field != null) {
|
||||
a = findAnnotation(field, annClass);
|
||||
if (a != findAnnotation(field, annClass, databasePlatform.getClass())) {
|
||||
System.out.println("Difference (field) " + field + ", " + annClass);
|
||||
}
|
||||
}
|
||||
if (a == null) {
|
||||
Method m = prop.getReadMethod();
|
||||
if (m != null) {
|
||||
a = findAnnotation(m, annClass);
|
||||
Method method = prop.getReadMethod();
|
||||
if (method != null) {
|
||||
a = findAnnotation(method, annClass);
|
||||
if (a != findAnnotation(method, annClass, databasePlatform.getClass())) {
|
||||
System.out.println("Difference (method) " + method + ", " + annClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
protected <T extends Annotation> Set<T> getAll(DeployBeanProperty prop, Class<T> annClass) {
|
||||
Set<T> ret = null;
|
||||
Field field = prop.getField();
|
||||
if (field != null) {
|
||||
ret = findAnnotations(field, annClass);
|
||||
}
|
||||
Method method = prop.getReadMethod();
|
||||
if (method != null) {
|
||||
if (ret != null) {
|
||||
ret.addAll(findAnnotations(method, annClass));
|
||||
} else {
|
||||
ret = findAnnotations(method, annClass);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
@@ -69,7 +108,7 @@ public abstract class AnnotationBase {
|
||||
protected <T extends Annotation> T find(DeployBeanProperty prop, Class<T> annClass) {
|
||||
T a = get(prop, annClass);
|
||||
if (a == null) {
|
||||
a = findAnnotation(prop.getOwningType(), annClass);
|
||||
a = findAnnotation(prop.getOwningType(), annClass, databasePlatform.getClass());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -91,6 +130,7 @@ public abstract class AnnotationBase {
|
||||
* <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!
|
||||
* It also does not filter out platform dependent annotations!
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
@@ -132,6 +172,19 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first annotation of a type for this platform. (if annotation is platform specific, otherwise first
|
||||
* found annotation is returned)
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType,
|
||||
Class<? extends DatabasePlatform> databasePlatform) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
Set<A> anns = findAnnotations(annotatedElement, annotationType);
|
||||
return getPlatformMatchingAnnotation(anns, databasePlatform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
@@ -139,7 +192,7 @@ public abstract class AnnotationBase {
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
|
||||
|
||||
Annotation[] anns = annotatedElement.getDeclaredAnnotations();
|
||||
Annotation[] anns = annotatedElement.getAnnotations(); // directly annotatated or inherited
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
@@ -155,4 +208,144 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all {@link Annotation}s 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!
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findAnnotations(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
Set<A> ret = new LinkedHashSet<A>();
|
||||
findMetaAnnotations(annotatedElement, annotationType, ret, new HashSet<Annotation>());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> void findMetaAnnotations(AnnotatedElement annotatedElement, Class<A> annotationType, Set<A> ret, Set<Annotation> visited) {
|
||||
|
||||
Annotation[] anns = annotatedElement.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
ret.add((A) ann);
|
||||
} else {
|
||||
Method repeatableValueMethod = getRepeatableValueMethod(ann, annotationType);
|
||||
if (repeatableValueMethod != null) {
|
||||
try {
|
||||
A[] repeatedAnns = (A[]) repeatableValueMethod.invoke(ann);
|
||||
for (Annotation repeatedAnn : repeatedAnns) {
|
||||
ret.add((A) repeatedAnn);
|
||||
findMetaAnnotations(repeatedAnn.annotationType(), annotationType, ret, visited);
|
||||
}
|
||||
} catch (Exception e) { // catch all exceptions (thrown by invoke)
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
findMetaAnnotations(ann.annotationType(), annotationType, ret, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// caches for getRepeatableValueMethod
|
||||
private static final Method getNullMethod() {
|
||||
try {
|
||||
return AnnotationBase.class.getDeclaredMethod("getNullMethod");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Annotation, Method> valueMethods = new ConcurrentHashMap<Annotation, Method>();
|
||||
private static final Method nullMethod = getNullMethod();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the <code>value()</code> method for a possible containerAnnotation.
|
||||
* Method is retuned only, if its signature is <code>array of containingType</code>.
|
||||
*/
|
||||
private static <A extends Annotation> Method getRepeatableValueMethod(
|
||||
Annotation containerAnnotation, Class<A> containingType) {
|
||||
|
||||
Method method = valueMethods.get(containerAnnotation);
|
||||
if (method == null) {
|
||||
try {
|
||||
method = containerAnnotation.annotationType().getMethod("value");
|
||||
} catch (NoSuchMethodException e) {
|
||||
method = nullMethod;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Method prev = valueMethods.putIfAbsent(containerAnnotation, method);
|
||||
method = prev == null ? method : prev;
|
||||
}
|
||||
if (method != nullMethod) {
|
||||
Class<?> retType = method.getReturnType();
|
||||
if (retType.isArray() && retType.getComponentType() == containingType) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a suitable annotation from <code>Set<T> anns</code> for this platform.
|
||||
* To distinguish between platforms, annotation type <code>T</code> must define
|
||||
* a method withthis signature:
|
||||
* <p>
|
||||
* <code>Class<? extends DatabasePlatform>[] platforms() default {};</code>
|
||||
* </p>
|
||||
* The finding rules are:
|
||||
* <ol>
|
||||
* <li>Check if T has method "platforms" if not, return <code>ann[0]</code></code>
|
||||
* <li>find the annotation that is defined for <code>databasePlatform</code></li>
|
||||
* <li>otherwise return the annotation for default platform (platforms = {})</li>
|
||||
* <li>return null
|
||||
* </ol>
|
||||
* (This mechanism is currently used by {@link Where} and {@link Formula})
|
||||
*/
|
||||
public static <T extends Annotation> T getPlatformMatchingAnnotation(Set<T> anns, Class<? extends DatabasePlatform> databasePlatform) {
|
||||
if (anns.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Method getPlatformsMethod = null;
|
||||
T fallback = null;
|
||||
for (T ann : anns) {
|
||||
try {
|
||||
if (getPlatformsMethod == null) {
|
||||
getPlatformsMethod = ann.getClass().getMethod("platforms");
|
||||
}
|
||||
if (!Class[].class.isAssignableFrom(getPlatformsMethod.getReturnType())) {
|
||||
return ann;
|
||||
}
|
||||
Class<?>[] platforms = (Class[]) getPlatformsMethod.invoke(ann);
|
||||
if (platforms.length == 0) {
|
||||
fallback = ann;
|
||||
} else {
|
||||
for (Class<?> platform : platforms) {
|
||||
if (databasePlatform.isAssignableFrom(platform)) {
|
||||
return ann;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
return ann; // not platform specific - return first one
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
@@ -119,15 +121,8 @@ public class AnnotationClass extends AnnotationParser {
|
||||
descriptor.setName("Embeddable:" + cls.getSimpleName());
|
||||
}
|
||||
|
||||
Indices indices = AnnotationBase.findAnnotation(cls, Indices.class);
|
||||
if (indices != null) {
|
||||
for (Index index: indices.value()) {
|
||||
descriptor.addIndex(new IndexDefinition(index.columnNames(), index.name(), index.unique()));
|
||||
}
|
||||
}
|
||||
|
||||
Index index = AnnotationBase.findAnnotation(cls,Index.class);
|
||||
if (index != null) {
|
||||
Set<Index> indices = AnnotationBase.findAnnotations(cls, Index.class);
|
||||
for (Index index: indices) {
|
||||
descriptor.addIndex(new IndexDefinition(index.columnNames(), index.name(), index.unique()));
|
||||
}
|
||||
|
||||
@@ -188,15 +183,8 @@ public class AnnotationClass extends AnnotationParser {
|
||||
descriptor.setCache(cache);
|
||||
}
|
||||
|
||||
NamedQueries namedQueries = AnnotationBase.findAnnotation(cls,NamedQueries.class);
|
||||
if (namedQueries != null) {
|
||||
for (NamedQuery namedQuery : namedQueries.value()) {
|
||||
descriptor.addNamedQuery(namedQuery.name(), namedQuery.query());
|
||||
}
|
||||
}
|
||||
|
||||
NamedQuery namedQuery = AnnotationBase.findAnnotation(cls,NamedQuery.class);
|
||||
if (namedQuery != null) {
|
||||
Set<NamedQuery> namedQueries = AnnotationBase.findAnnotations(cls,NamedQuery.class);
|
||||
for (NamedQuery namedQuery : namedQueries) {
|
||||
descriptor.addNamedQuery(namedQuery.name(), namedQuery.query());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@@ -251,18 +252,19 @@ public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isNotNullOnAllValidationGroups(notNull.groups())) {
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
Size size = get(prop, Size.class);
|
||||
if (size != null) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
// explicitly specify a version column
|
||||
prop.setDbLength(size.max());
|
||||
}
|
||||
// take the max size of all @Size annotations
|
||||
int maxSize = -1;
|
||||
for (Size size : getAll(prop, Size.class)) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
if (maxSize !=1 && maxSize < Integer.MAX_VALUE) {
|
||||
prop.setDbLength(maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,15 +312,8 @@ public class AnnotationFields extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
Indices indices = get(prop, Indices.class);
|
||||
if (indices != null) {
|
||||
for (Index index: indices.value()) {
|
||||
addIndex(prop, index);
|
||||
}
|
||||
}
|
||||
|
||||
Index index = get(prop, Index.class);
|
||||
if (index != null) {
|
||||
Set<Index> indices = getAll(prop, Index.class);
|
||||
for (Index index: indices) {
|
||||
addIndex(prop, index);
|
||||
}
|
||||
}
|
||||
@@ -378,14 +373,6 @@ public class AnnotationFields extends AnnotationParser {
|
||||
get(prop, OneToOne.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation is on all validation groups and hence
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
private boolean isNotNullOnAllValidationGroups(Class<?>[] groups) {
|
||||
return groups.length == 0 || groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0]);
|
||||
}
|
||||
|
||||
private void setEncryption(DeployBeanProperty prop, boolean dbEncString, int dbLen) {
|
||||
|
||||
util.checkEncryptKeyManagerDefined(prop.getFullBeanName());
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.validation.groups.Default;
|
||||
|
||||
import com.avaje.ebean.annotation.EbeanDDL;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
@@ -52,17 +54,12 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
*/
|
||||
protected void readEmbeddedAttributeOverrides(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
AttributeOverrides attrOverrides = get(prop, AttributeOverrides.class);
|
||||
if (attrOverrides != null) {
|
||||
HashMap<String, String> propMap = new HashMap<String, String>();
|
||||
AttributeOverride[] aoArray = attrOverrides.value();
|
||||
for (int i = 0; i < aoArray.length; i++) {
|
||||
String propName = aoArray[i].name();
|
||||
String columnName = aoArray[i].column().name();
|
||||
|
||||
propMap.put(propName, columnName);
|
||||
Set<AttributeOverride> attrOverrides = getAll(prop, AttributeOverride.class);
|
||||
if (!attrOverrides.isEmpty()) {
|
||||
HashMap<String, String> propMap = new HashMap<>();
|
||||
for (AttributeOverride attrOverride : attrOverrides) {
|
||||
propMap.put(attrOverride.name(), attrOverride.column().name());
|
||||
}
|
||||
|
||||
prop.getDeployEmbedded().putAll(propMap);
|
||||
}
|
||||
|
||||
@@ -95,4 +92,22 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
prop.setSecondaryTable(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation groups are {@link Default} (respectively empty) or contains {@link EbeanDDL}
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
protected boolean isEbeanValidationGroups(Class<?>[] groups) {
|
||||
if (groups.length == 0
|
||||
|| groups.length == 1 && javax.validation.groups.Default.class.isAssignableFrom(groups[0])) {
|
||||
return true;
|
||||
} else {
|
||||
for (Class<?> group : groups) {
|
||||
if (EbeanDDL.class.isAssignableFrom(group)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user