Skip to content

Commit

Permalink
Fixed #308
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Dec 30, 2016
1 parent 62fd6ea commit b5bc852
Show file tree
Hide file tree
Showing 51 changed files with 557 additions and 336 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,17 @@ public abstract class AbstractAttribute<X, Y> implements Attribute<X, Y> {
protected final boolean subqueryMapping;
protected final boolean subview;

public AbstractAttribute(ManagedViewType<X> declaringType, Class<Y> javaType, Annotation mapping, Set<Class<?>> entityViews, BatchFetch batchFetch, String errorLocation) {
public AbstractAttribute(ManagedViewType<X> declaringType, Class<Y> javaType, Annotation mapping, Set<Class<?>> entityViews, BatchFetch batchFetch, String errorLocation, Set<String> errors) {
if (javaType == null) {
throw new IllegalArgumentException("The attribute type is not resolvable " + errorLocation);
errors.add("The attribute type is not resolvable " + errorLocation);
}

int batchSize;
if (batchFetch == null || batchFetch.size() == -1) {
batchSize = -1;
} else if (batchFetch.size() < 1) {
throw new IllegalArgumentException("Illegal batch fetch size defined at '" + errorLocation + "'! Use a value greater than 0!");
errors.add("Illegal batch fetch size defined at '" + errorLocation + "'! Use a value greater than 0!");
batchSize = Integer.MIN_VALUE;
} else {
batchSize = batchFetch.size();
}
Expand Down Expand Up @@ -142,10 +143,10 @@ public AbstractAttribute(ManagedViewType<X> declaringType, Class<Y> javaType, An
this.correlationProvider = null;

if (!subqueryExpression.isEmpty() && subqueryAlias.isEmpty()) {
throw new IllegalArgumentException("The subquery alias is empty although the subquery expression is not " + errorLocation);
errors.add("The subquery alias is empty although the subquery expression is not " + errorLocation);
}
if (subqueryProvider.getEnclosingClass() != null && !Modifier.isStatic(subqueryProvider.getModifiers())) {
throw new IllegalArgumentException("The subquery provider is defined as non-static inner class. Make it static, otherwise it can't be instantiated: " + errorLocation);
errors.add("The subquery provider is defined as non-static inner class. Make it static, otherwise it can't be instantiated: " + errorLocation);
}
} else if (mapping instanceof MappingCorrelated) {
MappingCorrelated mappingCorrelated = (MappingCorrelated) mapping;
Expand All @@ -169,10 +170,22 @@ public AbstractAttribute(ManagedViewType<X> declaringType, Class<Y> javaType, An
this.correlationProvider = mappingCorrelated.correlator();

if (correlationProvider.getEnclosingClass() != null && !Modifier.isStatic(correlationProvider.getModifiers())) {
throw new IllegalArgumentException("The correlation provider is defined as non-static inner class. Make it static, otherwise it can't be instantiated: " + errorLocation);
errors.add("The correlation provider is defined as non-static inner class. Make it static, otherwise it can't be instantiated: " + errorLocation);
}
} else {
throw new IllegalArgumentException("No mapping annotation could be found " + errorLocation);
errors.add("No mapping annotation could be found " + errorLocation);
this.mapping = null;
this.fetchStrategy = null;
this.batchSize = Integer.MIN_VALUE;
this.subqueryProvider = null;
this.id = false;
this.queryParameter = false;
this.subqueryMapping = false;
this.subqueryExpression = null;
this.subqueryAlias = null;
this.correlationBasis = null;
this.correlationResult = null;
this.correlationProvider = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -53,13 +52,14 @@ public abstract class AbstractMethodAttribute<X, Y> extends AbstractAttribute<X,
private final Map<String, AttributeFilterMapping> filterMappings;

@SuppressWarnings("unchecked")
protected AbstractMethodAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews) {
protected AbstractMethodAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews, Set<String> errors) {
super(viewType,
(Class<Y>) ReflectionUtils.getResolvedMethodReturnType(viewType.getJavaType(), method),
mapping,
entityViews,
AnnotationUtils.findAnnotation(method, BatchFetch.class),
"for the attribute '" + StringUtils.firstToLower(method.getName().substring(3)) + "' of the class '" + viewType.getJavaType().getName() + "'!");
"for the attribute '" + StringUtils.firstToLower(method.getName().substring(3)) + "' of the class '" + viewType.getJavaType().getName() + "'!",
errors);
this.name = StringUtils.firstToLower(method.getName().substring(3));

UpdatableMapping updatableMapping = AnnotationUtils.findAnnotation(method, UpdatableMapping.class);
Expand All @@ -76,41 +76,47 @@ protected AbstractMethodAttribute(ManagedViewType<X> viewType, Method method, An
}

this.javaMethod = method;
this.filterMappings = new HashMap<String, AttributeFilterMapping>();
Map<String, AttributeFilterMapping> filterMappings = new HashMap<String, AttributeFilterMapping>();

AttributeFilter filterMapping = AnnotationUtils.findAnnotation(method, AttributeFilter.class);
AttributeFilters filtersMapping = AnnotationUtils.findAnnotation(method, AttributeFilters.class);

if (filterMapping != null) {
if (filtersMapping != null) {
throw new IllegalArgumentException("Illegal occurrences of @Filter and @Filters on the attribute '" + name + "' of the class '" + viewType.getJavaType().getName() + "'!");
errors.add("Illegal occurrences of @Filter and @Filters on the attribute '" + name + "' of the class '" + viewType.getJavaType().getName() + "'!");
} else {
addFilterMapping(filterMapping, filterMappings, errors);
}

addFilterMapping(filterMapping);
} else if (filtersMapping != null) {
for (AttributeFilter f : filtersMapping.value()) {
addFilterMapping(f);
addFilterMapping(f, filterMappings, errors);
}
}

this.filterMappings = Collections.unmodifiableMap(filterMappings);

if (this.mapping != null && this.mapping.isEmpty()) {
throw new IllegalArgumentException("Illegal empty mapping for the attribute '" + name + "' of the class '" + viewType.getJavaType().getName() + "'!");
errors.add("Illegal empty mapping for the attribute '" + name + "' of the class '" + viewType.getJavaType().getName() + "'!");
}
}

private void addFilterMapping(AttributeFilter filterMapping) {
private void addFilterMapping(AttributeFilter filterMapping, Map<String, AttributeFilterMapping> filterMappings, Set<String> errors) {
String filterName = filterMapping.name();
boolean errorOccurred = false;

if (filterName.isEmpty()) {
filterName = name;

if (filterMappings.containsKey(filterName)) {
throw new IllegalArgumentException("Illegal duplicate filter name mapping '" + filterName + "' at attribute '" + name + "' of the class '" + getDeclaringType().getJavaType().getName() + "'!");
errorOccurred = true;
errors.add("Illegal duplicate filter name mapping '" + filterName + "' at attribute '" + name + "' of the class '" + getDeclaringType().getJavaType().getName() + "'!");
}
}

AttributeFilterMapping attributeFilterMapping = new AttributeFilterMappingImpl(this, filterName, filterMapping.value());
filterMappings.put(attributeFilterMapping.getName(), attributeFilterMapping);

if (!errorOccurred) {
AttributeFilterMapping attributeFilterMapping = new AttributeFilterMappingImpl(this, filterName, filterMapping.value(), errors);
filterMappings.put(attributeFilterMapping.getName(), attributeFilterMapping);
}
}

@Override
Expand Down Expand Up @@ -140,59 +146,53 @@ public AttributeFilterMapping getFilter(String filterName) {

@Override
public Set<AttributeFilterMapping> getFilters() {
return new HashSet<AttributeFilterMapping>(filterMappings.values());
return new SetView<AttributeFilterMapping>(filterMappings.values());
}

public Map<String, AttributeFilterMapping> getFilterMappings() {
return filterMappings;
}

public static String validate(ManagedViewType<?> viewType, Method m) {
// Concrete methods are not mapped
if (!Modifier.isAbstract(m.getModifiers()) || m.isBridge()) {
return null;
}

public static String extractAttributeName(Class<?> viewType, Method m) {
String attributeName;

// We only support bean style getters
if (ReflectionUtils.isSetter(m)) {
attributeName = StringUtils.firstToLower(m.getName().substring(3));
Method getter = ReflectionUtils.getGetter(viewType.getJavaType(), attributeName);
Method getter = ReflectionUtils.getGetter(viewType, attributeName);

if (getter == null) {
throw new RuntimeException("The setter '" + m.getName() + "' from the entity view '" + viewType.getJavaType().getName() + "' has no corresponding getter!");
throw new RuntimeException("The setter '" + m.getName() + "' from the entity view '" + viewType.getName() + "' has no corresponding getter!");
}

if (m.getParameterTypes()[0] != getter.getReturnType()) {
throw new IllegalArgumentException("The setter '" + m.getName() + "' of the class '" + viewType.getJavaType().getName()
throw new IllegalArgumentException("The setter '" + m.getName() + "' of the class '" + viewType.getName()
+ "' must accept an argument of the same type as it's corresponding getter returns!");
}

return null;
} else if (!ReflectionUtils.isGetter(m)) {
throw new IllegalArgumentException("The given method '" + m.getName() + "' from the entity view '" + viewType.getJavaType().getName()
throw new IllegalArgumentException("The given method '" + m.getName() + "' from the entity view '" + viewType.getName()
+ "' is no bean style getter or setter!");
} else {
int index = m.getName().startsWith("is") ? 2 : 3;
attributeName = StringUtils.firstToLower(m.getName().substring(index));
Method setter = ReflectionUtils.getSetter(viewType.getJavaType(), attributeName);
Method setter = ReflectionUtils.getSetter(viewType, attributeName);

if (setter != null && setter.getParameterTypes()[0] != m.getReturnType()) {
throw new IllegalArgumentException("The getter '" + m.getName() + "' of the class '" + viewType.getJavaType().getName()
throw new IllegalArgumentException("The getter '" + m.getName() + "' of the class '" + viewType.getName()
+ "' must have the same return type as it's corresponding setter accepts!");
}
}

if (m.getExceptionTypes().length > 0) {
throw new IllegalArgumentException("The given method '" + m.getName() + "' from the entity view '" + viewType.getJavaType().getName() + "' must not throw an exception!");
throw new IllegalArgumentException("The given method '" + m.getName() + "' from the entity view '" + viewType.getName() + "' must not throw an exception!");
}

return attributeName;
}

public static Annotation getMapping(ManagedViewType<?> viewType, Method m) {
Class<?> entityClass = viewType.getEntityClass();
Mapping mapping = AnnotationUtils.findAnnotation(m, Mapping.class);

if (mapping == null) {
Expand Down Expand Up @@ -231,18 +231,13 @@ public static Annotation getMapping(ManagedViewType<?> viewType, Method m) {
}

// Implicit mapping
String attributeName = StringUtils.firstToLower(m.getName().substring(3));
String attributeName;

// First check if a the same method exists in the entity class
boolean entityAttributeExists = ReflectionUtils.getMethod(entityClass, m.getName()) != null;
// If not, check if a field with the given attribute name exists in the entity class
entityAttributeExists = entityAttributeExists || ReflectionUtils.getField(entityClass, attributeName) != null;

if (!entityAttributeExists) {
throw new IllegalArgumentException("The entity class '" + entityClass.getName() + "' has no attribute '" + attributeName
+ "' that was implicitly mapped in entity view '" + viewType.getJavaType().getName() + "' in class '" + m.getDeclaringClass().getName() + "'");
if (m.getName().startsWith("is")) {
attributeName = StringUtils.firstToLower(m.getName().substring(2));
} else {
attributeName = StringUtils.firstToLower(m.getName().substring(3));
}

mapping = new MappingLiteral(attributeName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ public abstract class AbstractMethodMappingPluralAttribute<X, C, Y> extends Abst
private final Comparator<Y> comparator;

@SuppressWarnings("unchecked")
public AbstractMethodMappingPluralAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews, boolean sorted) {
super(viewType, method, mapping, entityViews);
public AbstractMethodMappingPluralAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews, boolean sorted, Set<String> errors) {
super(viewType, method, mapping, entityViews, errors);
Class<?>[] typeArguments = ReflectionUtils.getResolvedMethodReturnTypeArguments(viewType.getJavaType(), method);
this.elementType = (Class<Y>) typeArguments[typeArguments.length - 1];
if (elementType == null) {
throw new IllegalArgumentException("The element type is not resolvable " + "for the attribute '" + StringUtils.firstToLower(method.getName().substring(3)) + "' of the class '" + viewType.getJavaType().getName() + "'!");
errors.add("The element type is not resolvable " + "for the attribute '" + StringUtils.firstToLower(method.getName().substring(3)) + "' of the class '" + viewType.getJavaType().getName() + "'!");
}

this.subview = entityViews.contains(elementType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
*/
public abstract class AbstractMethodSingularAttribute<X, Y> extends AbstractMethodAttribute<X, Y> implements SingularAttribute<X, Y> {

public AbstractMethodSingularAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews) {
super(viewType, method, mapping, entityViews);
public AbstractMethodSingularAttribute(ManagedViewType<X> viewType, Method method, Annotation mapping, Set<Class<?>> entityViews, Set<String> errors) {
super(viewType, method, mapping, entityViews, errors);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,19 @@ public abstract class AbstractParameterAttribute<X, Y> extends AbstractAttribute
private final MappingConstructor<X> declaringConstructor;

@SuppressWarnings("unchecked")
public AbstractParameterAttribute(MappingConstructor<X> constructor, int index, Annotation mapping, Set<Class<?>> entityViews) {
public AbstractParameterAttribute(MappingConstructor<X> constructor, int index, Annotation mapping, Set<Class<?>> entityViews, Set<String> errors) {
super(constructor.getDeclaringType(),
(Class<Y>) constructor.getJavaConstructor().getParameterTypes()[index],
mapping,
entityViews,
findAnnotation(constructor.getJavaConstructor().getParameterAnnotations()[index], BatchFetch.class),
"for the parameter of the constructor '" + constructor.getJavaConstructor().toString() + "' at the index '" + index + "'!");
"for the parameter of the constructor '" + constructor.getJavaConstructor().toString() + "' at the index '" + index + "'!",
errors);
this.index = index;
this.declaringConstructor = constructor;

if (this.mapping != null && this.mapping.isEmpty()) {
throw new IllegalArgumentException("Illegal empty mapping for the parameter of the constructor '" + declaringConstructor.getJavaConstructor().toString()
errors.add("Illegal empty mapping for the parameter of the constructor '" + declaringConstructor.getJavaConstructor().toString()
+ "' at the index '" + index + "'!");
}
}
Expand All @@ -66,7 +67,7 @@ private static <T extends Annotation> T findAnnotation(Annotation[] parameterAnn
return null;
}

public static void validate(MappingConstructor<?> constructor, int index) {
public static void validate(MappingConstructor<?> constructor, int index, Set<String> errors) {
Annotation[] annotations = constructor.getJavaConstructor().getParameterAnnotations()[index];
boolean foundAnnotation = false;

Expand All @@ -81,7 +82,7 @@ public static void validate(MappingConstructor<?> constructor, int index) {
}

if (!foundAnnotation) {
throw new IllegalArgumentException("No MappingParameter annotation given for the parameter of the constructor '" + constructor.getJavaConstructor() + "' of the class '"
errors.add("No MappingParameter annotation given for the parameter of the constructor '" + constructor.getJavaConstructor() + "' of the class '"
+ constructor.getDeclaringType().getJavaType().getName() + "' at index '" + index + "'.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public abstract class AbstractParameterMappingPluralAttribute<X, C, Y> extends A
private final Comparator<Y> comparator;

@SuppressWarnings("unchecked")
public AbstractParameterMappingPluralAttribute(MappingConstructor<X> mappingConstructor, int index, Annotation mapping, Set<Class<?>> entityViews, boolean sorted) {
super(mappingConstructor, index, mapping, entityViews);
public AbstractParameterMappingPluralAttribute(MappingConstructor<X> mappingConstructor, int index, Annotation mapping, Set<Class<?>> entityViews, boolean sorted, Set<String> errors) {
super(mappingConstructor, index, mapping, entityViews, errors);
Type parameterType = mappingConstructor.getJavaConstructor().getGenericParameterTypes()[index];
Class<?>[] typeArguments = ReflectionUtils.resolveTypeArguments(mappingConstructor.getDeclaringType().getJavaType(), parameterType);
this.elementType = (Class<Y>) typeArguments[typeArguments.length - 1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
*/
public abstract class AbstractParameterSingularAttribute<X, Y> extends AbstractParameterAttribute<X, Y> implements SingularAttribute<X, Y> {

public AbstractParameterSingularAttribute(MappingConstructor<X> constructor, int index, Annotation mapping, Set<Class<?>> entityViews) {
super(constructor, index, mapping, entityViews);
public AbstractParameterSingularAttribute(MappingConstructor<X> constructor, int index, Annotation mapping, Set<Class<?>> entityViews, Set<String> errors) {
super(constructor, index, mapping, entityViews, errors);
}

@Override
Expand Down
Loading

0 comments on commit b5bc852

Please sign in to comment.