Browse Source

DATACMNS-34 - Improved algorithm to lookup preferred constructor.

Algorithm is now was follows:

1. If there's no explicit constructor use the default constructor.
2. If there's a single explicit constructor, use this one.
3. If there's multiple explicit constructors and one has been annotated with @PersistenceConstructor use the annotated one.
4. If there's multiple explicit constructors and none annotated use the no-arg one or throw an exception to resolve the ambiguity.

Test cases for that algorithm are located in PreferredConstructorDiscovererUnitTests. Refactored PreferredConstructor and Parameter classes a little to make them immutable value objects. Introduced ability to lookup parameter TypeInformation for constructors on TypeInformation interface.

Extended generics in mapping subsystem to allow defining a concrete subtype of PersistentProperty as well. Removed some generics related compiler warnings as well.
pull/2/head
Oliver Gierke 15 years ago
parent
commit
870d156adb
  1. 29
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java
  2. 22
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java
  3. 4
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java
  4. 5
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java
  5. 57
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java
  6. 148
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java
  7. 62
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java
  8. 58
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/MutablePersistentEntity.java
  9. 118
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/PreferredConstructorDiscoverer.java
  10. 4
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java
  11. 2
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContextAware.java
  12. 7
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContextAwareBeanPostProcessor.java
  13. 17
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/event/MappingContextEvent.java
  14. 20
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java
  15. 4
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java
  16. 16
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java
  17. 9
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java
  18. 97
      spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java
  19. 20
      spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Property.java
  20. 1
      spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DefaultRepositoryInformation.java
  21. 3
      spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java
  22. 11
      spring-data-commons-core/src/main/java/org/springframework/data/util/ArrayTypeDiscoverer.java
  23. 23
      spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java
  24. 49
      spring-data-commons-core/src/main/java/org/springframework/data/util/TypeDiscoverer.java
  25. 14
      spring-data-commons-core/src/main/java/org/springframework/data/util/TypeInformation.java
  26. 8
      spring-data-commons-core/src/main/java/org/springframework/data/util/TypeVariableTypeInformation.java
  27. 58
      spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java
  28. 2
      spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java
  29. 133
      spring-data-commons-core/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java
  30. 1
      spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java
  31. 66
      spring-data-commons-core/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java
  32. 2
      spring-data-commons-core/src/test/java/org/springframework/data/util/TypeDiscovererUnitTests.java

29
spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractMappingContext.java

@ -35,8 +35,6 @@ import java.util.concurrent.ConcurrentMap; @@ -35,8 +35,6 @@ import java.util.concurrent.ConcurrentMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.mapping.event.MappingContextEvent;
import org.springframework.data.mapping.model.MappingContext;
import org.springframework.data.mapping.model.MappingException;
@ -44,7 +42,6 @@ import org.springframework.data.mapping.model.PersistentEntity; @@ -44,7 +42,6 @@ import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.validation.Validator;
@ -58,12 +55,12 @@ import org.springframework.validation.Validator; @@ -58,12 +55,12 @@ import org.springframework.validation.Validator;
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, P extends PersistentProperty> implements MappingContext<E>, InitializingBean, ApplicationEventPublisherAware {
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>> implements MappingContext<E, P>, InitializingBean, ApplicationEventPublisherAware {
private static final Set<String> UNMAPPED_FIELDS = new HashSet<String>(Arrays.asList("class", "this$0"));
private ApplicationEventPublisher applicationEventPublisher;
private ConcurrentMap<TypeInformation, E> persistentEntities = new ConcurrentHashMap<TypeInformation, E>();
private ConcurrentMap<TypeInformation<?>, E> persistentEntities = new ConcurrentHashMap<TypeInformation<?>, E>();
private ConcurrentMap<E, List<Validator>> validators = new ConcurrentHashMap<E, List<Validator>>();
private List<Class<?>> customSimpleTypes = new ArrayList<Class<?>>();
private Set<? extends Class<?>> initialEntitySet = new HashSet<Class<?>>();
@ -114,14 +111,14 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -114,14 +111,14 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
*/
public E getPersistentEntity(Class<?> type) {
return getPersistentEntity(new ClassTypeInformation(type));
return getPersistentEntity(ClassTypeInformation.from(type));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.MappingContext#getPersistentEntity(org.springframework.data.util.TypeInformation)
*/
public E getPersistentEntity(TypeInformation type) {
public E getPersistentEntity(TypeInformation<?> type) {
E entity = persistentEntities.get(type);
@ -144,7 +141,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -144,7 +141,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
*/
protected E addPersistentEntity(Class<?> type) {
return addPersistentEntity(new ClassTypeInformation(type));
return addPersistentEntity(ClassTypeInformation.from(type));
}
/**
@ -153,7 +150,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -153,7 +150,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
* @param typeInformation
* @return
*/
protected E addPersistentEntity(TypeInformation typeInformation) {
protected E addPersistentEntity(TypeInformation<?> typeInformation) {
E persistentEntity = persistentEntities.get(typeInformation);
@ -195,7 +192,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -195,7 +192,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
entity.setIdProperty(property);
}
TypeInformation nestedType = getNestedTypeToAdd(property, entity);
TypeInformation<?> nestedType = getNestedTypeToAdd(property, entity);
if (nestedType != null) {
addPersistentEntity(nestedType);
}
@ -212,11 +209,11 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -212,11 +209,11 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
// Inform listeners
if (null != applicationEventPublisher) {
applicationEventPublisher.publishEvent(new MappingContextEvent(entity, typeInformation));
applicationEventPublisher.publishEvent(new MappingContextEvent<E, P>(entity, typeInformation));
}
// Cache
persistentEntities.put(entity.getPropertyInformation(), (E) entity);
persistentEntities.put(entity.getTypeInformation(), (E) entity);
return entity;
} catch (IntrospectionException e) {
@ -233,13 +230,13 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -233,13 +230,13 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
* @param property
* @return the TypeInformation to be added as {@link PersistentEntity} or {@literal
*/
private TypeInformation getNestedTypeToAdd(PersistentProperty property, PersistentEntity<?> entity) {
private TypeInformation<?> getNestedTypeToAdd(P property, PersistentEntity<?, P> entity) {
if (entity.getType().equals(property.getRawType())) {
return null;
}
TypeInformation typeInformation = property.getTypeInformation();
TypeInformation<?> typeInformation = property.getTypeInformation();
if (customSimpleTypes.contains(typeInformation.getType())) {
return null;
@ -260,7 +257,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -260,7 +257,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
return null;
}
private TypeInformation getTypeInformationIfNotSimpleType(TypeInformation information) {
private TypeInformation<?> getTypeInformationIfNotSimpleType(TypeInformation<?> information) {
return information == null || MappingBeanHelper.isSimpleType(information.getType()) ? null : information;
}
@ -268,7 +265,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>, @@ -268,7 +265,7 @@ public abstract class AbstractMappingContext<E extends BasicPersistentEntity<?>,
return validators.get(entity);
}
protected abstract E createPersistentEntity(TypeInformation typeInformation);
protected abstract <T> E createPersistentEntity(TypeInformation<T> typeInformation);
protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner);

22
spring-data-commons-core/src/main/java/org/springframework/data/mapping/AbstractPersistentProperty.java

@ -35,27 +35,29 @@ import org.springframework.data.util.TypeInformation; @@ -35,27 +35,29 @@ import org.springframework.data.util.TypeInformation;
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public abstract class AbstractPersistentProperty implements PersistentProperty {
public abstract class AbstractPersistentProperty<P extends PersistentProperty<P>> implements PersistentProperty<P> {
protected final String name;
protected final PropertyDescriptor propertyDescriptor;
protected final TypeInformation information;
protected final TypeInformation<?> information;
protected final Class<?> rawType;
protected final Field field;
protected final Association association;
protected final PersistentEntity<?> owner;
protected final Association<P> association;
protected final PersistentEntity<?, P> owner;
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?> owner) {
public AbstractPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner) {
this.name = field.getName();
this.rawType = field.getType();
this.information = owner.getPropertyInformation().getProperty(this.name);
this.information = owner.getTypeInformation().getProperty(this.name);
this.propertyDescriptor = propertyDescriptor;
this.field = field;
this.association = isAssociation() ? new Association(this, null) : null;
this.association = isAssociation() ? createAssociation() : null;
this.owner = owner;
}
protected abstract Association<P> createAssociation();
public PersistentEntity<?> getOwner() {
public PersistentEntity<?, P> getOwner() {
return owner;
}
@ -71,7 +73,7 @@ public abstract class AbstractPersistentProperty implements PersistentProperty { @@ -71,7 +73,7 @@ public abstract class AbstractPersistentProperty implements PersistentProperty {
return this.rawType;
}
public TypeInformation getTypeInformation() {
public TypeInformation<?> getTypeInformation() {
return information;
}
@ -104,7 +106,7 @@ public abstract class AbstractPersistentProperty implements PersistentProperty { @@ -104,7 +106,7 @@ public abstract class AbstractPersistentProperty implements PersistentProperty {
return false;
}
public Association getAssociation() {
public Association<P> getAssociation() {
return association;
}

4
spring-data-commons-core/src/main/java/org/springframework/data/mapping/AnnotationBasedPersistentProperty.java

@ -34,7 +34,7 @@ import org.springframework.data.mapping.model.PersistentProperty; @@ -34,7 +34,7 @@ import org.springframework.data.mapping.model.PersistentProperty;
*
* @author Oliver Gierke
*/
public class AnnotationBasedPersistentProperty extends AbstractPersistentProperty {
public abstract class AnnotationBasedPersistentProperty<P extends PersistentProperty<P>> extends AbstractPersistentProperty<P> {
private final Value value;
@ -46,7 +46,7 @@ public class AnnotationBasedPersistentProperty extends AbstractPersistentPropert @@ -46,7 +46,7 @@ public class AnnotationBasedPersistentProperty extends AbstractPersistentPropert
* @param owner
*/
public AnnotationBasedPersistentProperty(Field field,
PropertyDescriptor propertyDescriptor, PersistentEntity<?> owner) {
PropertyDescriptor propertyDescriptor, PersistentEntity<?, P> owner) {
super(field, propertyDescriptor, owner);
this.value = field.getAnnotation(Value.class);

5
spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java

@ -17,10 +17,11 @@ @@ -17,10 +17,11 @@
package org.springframework.data.mapping;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.model.PersistentProperty;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public interface AssociationHandler {
void doWithAssociation(Association association);
public interface AssociationHandler<P extends PersistentProperty<P>> {
void doWithAssociation(Association<P> association);
}

57
spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java

@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.data.mapping.model.MappingContext;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.util.TypeInformation;
/**
* Simple implementation of {@link MappingContext} creating {@link BasicPersistentEntity} and
* {@link AnnotationBasedPersistentProperty} instances.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class BasicMappingContext extends AbstractMappingContext<BasicPersistentEntity<?>, PersistentProperty> {
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
*/
@Override
@SuppressWarnings("rawtypes")
protected BasicPersistentEntity<?> createPersistentEntity(
TypeInformation typeInformation) {
return new BasicPersistentEntity(typeInformation);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.util.TypeInformation, org.springframework.data.mapping.BasicPersistentEntity)
*/
@Override
protected PersistentProperty createPersistentProperty(Field field,
PropertyDescriptor descriptor,
BasicPersistentEntity<?> owner) {
return new AnnotationBasedPersistentProperty(field, descriptor, owner);
}
}

148
spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java

@ -15,16 +15,10 @@ @@ -15,16 +15,10 @@
*/
package org.springframework.data.mapping;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.data.mapping.model.PersistentProperty;
@ -36,14 +30,13 @@ import org.springframework.data.util.TypeInformation; @@ -36,14 +30,13 @@ import org.springframework.data.util.TypeInformation;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class BasicPersistentEntity<T> implements PersistentEntity<T> {
public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implements MutablePersistentEntity<T, P> {
protected final Class<T> type;
protected final PreferredConstructor<T> preferredConstructor;
protected final TypeInformation information;
protected final Map<String, PersistentProperty> persistentProperties = new HashMap<String, PersistentProperty>();
protected final Map<String, Association> associations = new HashMap<String, Association>();
protected PersistentProperty idProperty;
protected final TypeInformation<T> information;
protected final Map<String, P> persistentProperties = new HashMap<String, P>();
protected final Map<String, Association<P>> associations = new HashMap<String, Association<P>>();
protected P idProperty;
/**
@ -51,131 +44,61 @@ public class BasicPersistentEntity<T> implements PersistentEntity<T> { @@ -51,131 +44,61 @@ public class BasicPersistentEntity<T> implements PersistentEntity<T> {
*
* @param information
*/
@SuppressWarnings("unchecked")
public BasicPersistentEntity(TypeInformation information) {
this.type = (Class<T>) information.getType();
public BasicPersistentEntity(TypeInformation<T> information) {
this.information = information;
this.preferredConstructor = getPreferredConstructor(type);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private final PreferredConstructor<T> getPreferredConstructor(Class<T> type) {
// Find the right constructor
PreferredConstructor<T> preferredConstructor = null;
for (Constructor<?> constructor : type.getDeclaredConstructors()) {
if (constructor.getParameterTypes().length != 0) {
// Non-no-arg constructor
if (null == preferredConstructor || constructor.isAnnotationPresent(PersistenceConstructor.class)) {
preferredConstructor = new PreferredConstructor<T>((Constructor<T>) constructor);
String[] paramNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(constructor);
Type[] paramTypes = constructor.getGenericParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> targetType = Object.class;
Class<?> rawType = constructor.getParameterTypes()[i];
if (paramTypes[i] instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) paramTypes[i];
targetType = getTargetType(ptype);
} else {
if (paramTypes[i] instanceof TypeVariable) {
targetType = getTargetType((TypeVariable) paramTypes[i]);
} else if (paramTypes[i] instanceof Class<?>) {
targetType = (Class<?>) paramTypes[i];
}
}
String paramName = (null != paramNames ? paramNames[i] : "param" + i);
preferredConstructor.addParameter(paramName, targetType, rawType, targetType.getDeclaredAnnotations());
}
if (constructor.isAnnotationPresent(PersistenceConstructor.class)) {
// We're done
break;
}
}
}
}
return preferredConstructor;
}
private Class<?> getTargetType(TypeVariable<?> tv) {
Class<?> targetType = Object.class;
Type[] bounds = tv.getBounds();
if (bounds.length > 0) {
if (bounds[0] instanceof ParameterizedType) {
return getTargetType((ParameterizedType) bounds[0]);
} else if (bounds[0] instanceof TypeVariable) {
return getTargetType((TypeVariable<?>) bounds[0]);
} else {
targetType = (Class<?>) bounds[0];
}
}
return targetType;
}
private Class<?> getTargetType(ParameterizedType ptype) {
Class<?> targetType = Object.class;
Type[] types = ptype.getActualTypeArguments();
if (types.length == 1) {
if (types[0] instanceof TypeVariable) {
// Placeholder type
targetType = Object.class;
} else {
if (types[0] instanceof ParameterizedType) {
return getTargetType((ParameterizedType) types[0]);
} else {
targetType = (Class<?>) types[0];
}
}
} else {
targetType = (Class<?>) ptype.getRawType();
}
return targetType;
}
this.preferredConstructor = new PreferredConstructorDiscoverer<T>(information).getConstructor();
}
public PreferredConstructor<T> getPreferredConstructor() {
return preferredConstructor;
}
public String getName() {
return type.getName();
return getType().getName();
}
public PersistentProperty getIdProperty() {
public P getIdProperty() {
return idProperty;
}
public void setIdProperty(PersistentProperty property) {
/* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#setIdProperty(P)
*/
public void setIdProperty(P property) {
idProperty = property;
}
public Collection<PersistentProperty> getPersistentProperties() {
public Collection<P> getPersistentProperties() {
return persistentProperties.values();
}
public void addPersistentProperty(PersistentProperty property) {
/* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
*/
public void addPersistentProperty(P property) {
persistentProperties.put(property.getName(), property);
}
public Collection<Association> getAssociations() {
public Collection<Association<P>> getAssociations() {
return associations.values();
}
public void addAssociation(Association association) {
/* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#addAssociation(org.springframework.data.mapping.model.Association)
*/
public void addAssociation(Association<P> association) {
associations.put(association.getInverse().getName(), association);
}
public PersistentProperty getPersistentProperty(String name) {
public P getPersistentProperty(String name) {
return persistentProperties.get(name);
}
public Class<T> getType() {
return type;
return information.getType();
}
public TypeInformation getPropertyInformation() {
public TypeInformation<T> getTypeInformation() {
return information;
}
@ -183,24 +106,23 @@ public class BasicPersistentEntity<T> implements PersistentEntity<T> { @@ -183,24 +106,23 @@ public class BasicPersistentEntity<T> implements PersistentEntity<T> {
return persistentProperties.keySet();
}
public void doWithProperties(PropertyHandler handler) {
for (PersistentProperty property : persistentProperties.values()) {
if (!property.isTransient() && !property.isAssociation() && !property.isIdProperty()) {
public void doWithProperties(PropertyHandler<P> handler) {
for (P property : persistentProperties.values()) {
if (!property.isTransient() && !property.isAssociation()) {
handler.doWithPersistentProperty(property);
}
}
}
public void doWithAssociations(AssociationHandler handler) {
for (Association association : associations.values()) {
public void doWithAssociations(AssociationHandler<P> handler) {
for (Association<P> association : associations.values()) {
handler.doWithAssociation(association);
}
}
/**
* Callback method to trigger validation of the {@link PersistentEntity}. As {@link BasicPersistentEntity} is not
* immutable there might be some verification steps necessary after the object has reached is final state.
*/
/* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#verify()
*/
public void verify() {
}

62
spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java

@ -32,17 +32,18 @@ import java.util.concurrent.ConcurrentHashMap; @@ -32,17 +32,18 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.mapping.model.MappingInstantiationException;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.mapping.model.PreferredConstructor;
import org.springframework.data.mapping.model.PreferredConstructor.Parameter;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ReflectionUtils;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
@ -106,12 +107,12 @@ public abstract class MappingBeanHelper { @@ -106,12 +107,12 @@ public abstract class MappingBeanHelper {
return type.isEnum();
}
public static <T> T constructInstance(PersistentEntity<T> entity, PreferredConstructor.ParameterValueProvider provider) {
public static <T, P extends PersistentProperty<P>> T constructInstance(PersistentEntity<T, P> entity, PreferredConstructor.ParameterValueProvider provider) {
return constructInstance(entity, provider, new StandardEvaluationContext());
}
@SuppressWarnings({"unchecked"})
public static <T> T constructInstance(PersistentEntity<T> entity, PreferredConstructor.ParameterValueProvider provider, EvaluationContext spelCtx) {
public static <T, P extends PersistentProperty<P>> T constructInstance(PersistentEntity<T, P> entity, PreferredConstructor.ParameterValueProvider provider, EvaluationContext spelCtx) {
PreferredConstructor<T> constructor = entity.getPreferredConstructor();
if (null == constructor) {
@ -135,11 +136,11 @@ public abstract class MappingBeanHelper { @@ -135,11 +136,11 @@ public abstract class MappingBeanHelper {
List<Object> params = new LinkedList<Object>();
if (null != provider && constructor.getParameters().size() > 0) {
for (PreferredConstructor.Parameter parameter : constructor.getParameters()) {
Value v = parameter.getValue();
for (Parameter<?> parameter : constructor.getParameters()) {
String key = parameter.getKey();
Object obj;
if (null != v) {
Expression x = parser.parseExpression(v.value());
if (null != key) {
Expression x = parser.parseExpression(key);
obj = x.getValue(spelCtx);
} else {
obj = provider.getParameterValue(parameter);
@ -159,40 +160,51 @@ public abstract class MappingBeanHelper { @@ -159,40 +160,51 @@ public abstract class MappingBeanHelper {
}
public static void setProperty(Object on,
PersistentProperty property,
PersistentProperty<?> property,
Object value)
throws IllegalAccessException, InvocationTargetException {
setProperty(on, property, value, false);
}
public static void setProperty(Object on,
PersistentProperty property,
PersistentProperty<?> property,
Object value,
boolean fieldAccessOnly)
throws IllegalAccessException, InvocationTargetException {
Field field = property.getField();
Method setter = (null != property.getPropertyDescriptor() ? property.getPropertyDescriptor().getWriteMethod() : null);
if (fieldAccessOnly || null == setter) {
if (null != value && value.getClass().isAssignableFrom(field.getType())) {
field.set(on, value);
} else {
field.set(on, conversionService.convert(value, field.getType()));
}
return;
}
Method setter = property.getPropertyDescriptor() != null ? property.getPropertyDescriptor().getWriteMethod() : null;
if (fieldAccessOnly || null == setter) {
Object valueToSet = getPotentiallyConvertedValue(value, property.getType());
ReflectionUtils.makeAccessible(property.getField());
ReflectionUtils.setField(property.getField(), on, valueToSet);
return;
}
Class<?>[] paramTypes = setter.getParameterTypes();
if (null != value && paramTypes.length > 0 && !value.getClass().isAssignableFrom(paramTypes[0])) {
setter.invoke(on, conversionService.convert(value, paramTypes[0]));
} else {
setter.invoke(on, value);
}
Object valueToSet = getPotentiallyConvertedValue(value, paramTypes[0]);
ReflectionUtils.makeAccessible(setter);
ReflectionUtils.invokeMethod(setter, on, valueToSet);
}
/**
* Converts the given source value if it is not assignable to the given target type.
*
* @param source
* @param targetType
* @return
*/
private static Object getPotentiallyConvertedValue(Object source, Class<?> targetType) {
if (source != null && source.getClass().isAssignableFrom(targetType)) {
return source;
}
return conversionService.convert(source, targetType);
}
@SuppressWarnings({"unchecked"})
public static <T> T getProperty(Object from,
PersistentProperty property,
PersistentProperty<?> property,
Class<T> type,
boolean fieldAccessOnly)
throws IllegalAccessException, InvocationTargetException {

58
spring-data-commons-core/src/main/java/org/springframework/data/mapping/MutablePersistentEntity.java

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.data.mapping.model.PersistentProperty;
/**
* Interface capturing mutator methods for {@link PersistentEntity}s.
*
* @author Oliver Gierke
*/
public interface MutablePersistentEntity<T, P extends PersistentProperty<P>>
extends PersistentEntity<T, P> {
/**
* Sets the id property for the entity.
*
* @param property
*/
void setIdProperty(P property);
/**
* Adds a {@link PersistentProperty} to the entity.
*
* @param property
*/
void addPersistentProperty(P property);
/**
* Adds an {@link Association} to the entity.
*
* @param association
*/
void addAssociation(Association<P> association);
/**
* Callback method to trigger validation of the {@link PersistentEntity}. As
* {@link MutablePersistentEntity} is not immutable there might be some
* verification steps necessary after the object has reached is final state.
*/
void verify();
}

118
spring-data-commons-core/src/main/java/org/springframework/data/mapping/PreferredConstructorDiscoverer.java

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.List;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.data.mapping.model.PreferredConstructor;
import org.springframework.data.mapping.model.PreferredConstructor.Parameter;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
/**
* Helper class to find a {@link PreferredConstructor}.
*
* @author Oliver Gierke
*/
public class PreferredConstructorDiscoverer<T> {
private final ParameterNameDiscoverer nameDiscoverer =
new LocalVariableTableParameterNameDiscoverer();
private PreferredConstructor<T> constructor;
public PreferredConstructorDiscoverer(Class<T> type) {
this(ClassTypeInformation.from(type));
}
/**
* Creates a new {@link PreferredConstructorDiscoverer} for the given type.
*
* @param owningType
*/
protected PreferredConstructorDiscoverer(TypeInformation<T> owningType) {
boolean noArgConstructorFound = false;
int numberOfArgConstructors = 0;
Class<?> rawOwningType = owningType.getType();
for (Constructor<?> constructor : rawOwningType.getDeclaredConstructors()) {
PreferredConstructor<T> preferredConstructor =
buildPreferredConstructor(constructor, owningType);
// Explicitly defined constructor trumps all
if (preferredConstructor.isExplicitlyAnnotated()) {
this.constructor = preferredConstructor;
return;
}
// No-arg constructor trumps custom ones
if (this.constructor == null || preferredConstructor.isNoArgConstructor()) {
this.constructor = preferredConstructor;
}
if (preferredConstructor.isNoArgConstructor()) {
noArgConstructorFound = true;
} else {
numberOfArgConstructors++;
}
}
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
throw new IllegalArgumentException(
"Multiple no-arg constructors found! Annotate one with @PreferedConstructor explicitly to select it to be used in persistence operations.");
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private PreferredConstructor<T> buildPreferredConstructor(
Constructor<?> constructor, TypeInformation<T> typeInformation) {
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
if (parameterTypes.isEmpty()) {
return new PreferredConstructor<T>((Constructor<T>) constructor);
}
String[] parameterNames = nameDiscoverer.getParameterNames(constructor);
Parameter<?>[] parameters = new Parameter[parameterTypes.size()];
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
for (int i = 0; i < parameterTypes.size(); i++) {
String name = parameterNames == null ? null : parameterNames[i];
TypeInformation<?> type = parameterTypes.get(i);
Annotation[] annotations = parameterAnnotations[i];
parameters[i] = new Parameter(name, type, annotations);
}
return new PreferredConstructor<T>((Constructor<T>) constructor,
parameters);
}
public PreferredConstructor<T> getConstructor() {
return constructor;
}
}

4
spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java

@ -24,7 +24,7 @@ import org.springframework.data.mapping.model.PersistentProperty; @@ -24,7 +24,7 @@ import org.springframework.data.mapping.model.PersistentProperty;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public interface PropertyHandler {
public interface PropertyHandler<P extends PersistentProperty<P>> {
void doWithPersistentProperty(PersistentProperty persistentProperty);
void doWithPersistentProperty(P persistentProperty);
}

2
spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContextAware.java

@ -30,6 +30,6 @@ public interface MappingContextAware { @@ -30,6 +30,6 @@ public interface MappingContextAware {
*
* @param mappingContext
*/
void setMappingContext(MappingContext<?> mappingContext);
void setMappingContext(MappingContext<?, ?> mappingContext);
}

7
spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/MappingContextAwareBeanPostProcessor.java

@ -35,12 +35,12 @@ public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor, @@ -35,12 +35,12 @@ public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor,
private ApplicationContext applicationContext;
private String mappingContextBeanName = "mappingContext";
private MappingContext mappingContext;
private MappingContext<?, ?> mappingContext;
public MappingContextAwareBeanPostProcessor() {
}
public MappingContextAwareBeanPostProcessor(MappingContext mappingContext) {
public MappingContextAwareBeanPostProcessor(MappingContext<?, ?> mappingContext) {
this.mappingContext = mappingContext;
}
@ -60,7 +60,8 @@ public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor, @@ -60,7 +60,8 @@ public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor,
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
@SuppressWarnings("rawtypes")
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MappingContextAware) {
if (null == mappingContext) {
Map<String, MappingContext> mappingContexts = applicationContext.getBeansOfType(MappingContext.class);

17
spring-data-commons-core/src/main/java/org/springframework/data/mapping/event/MappingContextEvent.java

@ -18,27 +18,28 @@ package org.springframework.data.mapping.event; @@ -18,27 +18,28 @@ package org.springframework.data.mapping.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.util.TypeInformation;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class MappingContextEvent extends ApplicationEvent {
public class MappingContextEvent<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> extends ApplicationEvent {
private static final long serialVersionUID = 1336466833846092490L;
private TypeInformation typeInformation;
private TypeInformation<?> typeInformation;
public MappingContextEvent(PersistentEntity<?> source, TypeInformation typeInformation) {
public MappingContextEvent(E source, TypeInformation<?> typeInformation) {
super(source);
this.typeInformation = typeInformation;
}
public TypeInformation getTypeInformation() {
public TypeInformation<?> getTypeInformation() {
return typeInformation;
}
public PersistentEntity<?> getPersistentEntity() {
return (PersistentEntity<?>) source;
}
@SuppressWarnings("unchecked")
public E getPersistentEntity() {
return (E) source;
}
}

20
spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java

@ -19,29 +19,21 @@ package org.springframework.data.mapping.model; @@ -19,29 +19,21 @@ package org.springframework.data.mapping.model;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
public class Association {
public class Association<P extends PersistentProperty<P>> {
protected PersistentProperty inverse;
protected PersistentProperty obverse;
protected P inverse;
protected P obverse;
public Association(PersistentProperty inverse, PersistentProperty obverse) {
public Association(P inverse, P obverse) {
this.inverse = inverse;
this.obverse = obverse;
}
public PersistentProperty getInverse() {
public P getInverse() {
return inverse;
}
public void setInverse(PersistentProperty inverse) {
this.inverse = inverse;
}
public PersistentProperty getObverse() {
public P getObverse() {
return obverse;
}
public void setObverse(PersistentProperty obverse) {
this.obverse = obverse;
}
}

4
spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java

@ -35,7 +35,7 @@ import org.springframework.validation.Validator; @@ -35,7 +35,7 @@ import org.springframework.validation.Validator;
* @author Jon Brisbin
* @author Oliver Gierke
*/
public interface MappingContext<E extends PersistentEntity<?>> {
public interface MappingContext<E extends PersistentEntity<?, P>, P extends PersistentProperty<P>> {
/**
* Obtains a list of PersistentEntity instances
@ -46,7 +46,7 @@ public interface MappingContext<E extends PersistentEntity<?>> { @@ -46,7 +46,7 @@ public interface MappingContext<E extends PersistentEntity<?>> {
E getPersistentEntity(Class<?> type);
E getPersistentEntity(TypeInformation type);
E getPersistentEntity(TypeInformation<?> type);
/**
* Obtains a validator for the given entity

16
spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java

@ -14,7 +14,7 @@ import java.util.Collection; @@ -14,7 +14,7 @@ import java.util.Collection;
* @author Jon Brisbin
* @author Oliver Gierke
*/
public interface PersistentEntity<T> {
public interface PersistentEntity<T, P extends PersistentProperty<P>> {
/**
* The entity name including any package prefix
@ -33,21 +33,21 @@ public interface PersistentEntity<T> { @@ -33,21 +33,21 @@ public interface PersistentEntity<T> {
*
* @return the id property of the {@link PersistentEntity}.
*/
PersistentProperty getIdProperty();
P getIdProperty();
/**
* A list of properties to be persisted
*
* @return A list of PersistentProperty instances
*/
Collection<PersistentProperty> getPersistentProperties();
Collection<P> getPersistentProperties();
/**
* A list of the associations for this entity. This is typically a subset of the list returned by {@link #getPersistentProperties()}
*
* @return A list of associations
*/
Collection<Association> getAssociations();
Collection<Association<P>> getAssociations();
/**
* Obtains a PersistentProperty instance by name
@ -55,14 +55,14 @@ public interface PersistentEntity<T> { @@ -55,14 +55,14 @@ public interface PersistentEntity<T> {
* @param name The name of the property
* @return The PersistentProperty or null if it doesn't exist
*/
PersistentProperty getPersistentProperty(String name);
P getPersistentProperty(String name);
/**
* @return The underlying Java class for this entity
*/
Class<T> getType();
TypeInformation getPropertyInformation();
TypeInformation<T> getTypeInformation();
/**
* A list of property names
@ -71,7 +71,7 @@ public interface PersistentEntity<T> { @@ -71,7 +71,7 @@ public interface PersistentEntity<T> {
*/
Collection<String> getPersistentPropertyNames();
void doWithProperties(PropertyHandler handler);
void doWithProperties(PropertyHandler<P> handler);
void doWithAssociations(AssociationHandler handler);
void doWithAssociations(AssociationHandler<P> handler);
}

9
spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java

@ -5,7 +5,6 @@ import java.lang.reflect.Field; @@ -5,7 +5,6 @@ import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.util.TypeInformation;
/**
@ -13,9 +12,9 @@ import org.springframework.data.util.TypeInformation; @@ -13,9 +12,9 @@ import org.springframework.data.util.TypeInformation;
* @author Jon Brisbin
* @author Oliver Gierke
*/
public interface PersistentProperty {
public interface PersistentProperty<P extends PersistentProperty<P>> {
PersistentEntity<?> getOwner();
PersistentEntity<?, P> getOwner();
/**
* The name of the property
@ -31,7 +30,7 @@ public interface PersistentProperty { @@ -31,7 +30,7 @@ public interface PersistentProperty {
*/
Class<?> getType();
TypeInformation getTypeInformation();
TypeInformation<?> getTypeInformation();
PropertyDescriptor getPropertyDescriptor();
@ -43,7 +42,7 @@ public interface PersistentProperty { @@ -43,7 +42,7 @@ public interface PersistentProperty {
boolean isAssociation();
Association getAssociation();
Association<P> getAssociation();
boolean isCollection();

97
spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java

@ -18,78 +18,101 @@ package org.springframework.data.mapping.model; @@ -18,78 +18,101 @@ package org.springframework.data.mapping.model;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* Value object to encapsulate the constructor to be used when mapping persistent data to objects.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class PreferredConstructor<T> {
protected Constructor<T> constructor;
protected List<Parameter> parameters = new LinkedList<Parameter>();
private final Constructor<T> constructor;
private final List<Parameter<?>> parameters;
public PreferredConstructor(Constructor<T> constructor) {
public PreferredConstructor(Constructor<T> constructor, Parameter<?>... parameters) {
ReflectionUtils.makeAccessible(constructor);
this.constructor = constructor;
this.parameters = Arrays.asList(parameters);
}
public Constructor<T> getConstructor() {
return constructor;
}
public List<Parameter> getParameters() {
public List<Parameter<?>> getParameters() {
return parameters;
}
public void addParameter(String name, Class<?> type, Class<?> rawType, Annotation[] annotations) {
parameters.add(new Parameter(name, type, rawType, annotations));
/**
* Returns whether the constructor does not have any arguments.
*
* @return
*/
public boolean isNoArgConstructor() {
return parameters.isEmpty();
}
/**
* Returns whether the constructor was explicitly selected (by {@link PersistenceConstructor}).
*
* @return
*/
public boolean isExplicitlyAnnotated() {
return constructor.isAnnotationPresent(PersistenceConstructor.class);
}
public static class Parameter {
protected final String name;
protected final Class<?> type;
protected final Class<?> rawType;
protected final Annotation[] annotations;
protected Value value;
public Parameter(String name, Class<?> type, Class<?> rawType, Annotation[] annotations) {
this.name = name;
this.type = type;
this.rawType = rawType;
this.annotations = annotations;
for (Annotation anno : annotations) {
if (anno.annotationType() == Value.class) {
this.value = (Value) anno;
break;
}
}
public static class Parameter<T> {
private final String name;
private final TypeInformation<T> type;
private final String key;
public Parameter(String name, TypeInformation<T> type, Annotation[] annotations) {
Assert.notNull(type);
Assert.notNull(annotations);
this.name = name;
this.type = type;
this.key = getValue(annotations);
}
private String getValue(Annotation[] annotations) {
for (Annotation anno : annotations) {
if (anno.annotationType() == Value.class) {
return ((Value) anno).value();
}
}
return null;
}
public String getName() {
return name;
}
public Class<?> getType() {
public TypeInformation<T> getType() {
return type;
}
public Class<?> getRawType() {
return rawType;
}
public Annotation[] getAnnotations() {
return annotations;
public Class<T> getRawType() {
return type.getType();
}
public Value getValue() {
return value;
public String getKey() {
return key;
}
}
public static interface ParameterValueProvider {
Object getParameterValue(Parameter parameter);
<T> T getParameterValue(Parameter<T> parameter);
}
}

20
spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/Property.java

@ -36,7 +36,7 @@ public class Property { @@ -36,7 +36,7 @@ public class Property {
private static String ERROR_TEMPLATE = "No property %s found for type %s";
private final String name;
private final TypeInformation type;
private final TypeInformation<?> type;
private final boolean isCollection;
private Property next;
@ -51,16 +51,16 @@ public class Property { @@ -51,16 +51,16 @@ public class Property {
*/
Property(String name, Class<?> owningType) {
this(name, new ClassTypeInformation(owningType));
this(name, ClassTypeInformation.from(owningType));
}
Property(String name, TypeInformation owningType) {
Property(String name, TypeInformation<?> owningType) {
Assert.hasText(name);
Assert.notNull(owningType);
String propertyName = StringUtils.uncapitalize(name);
TypeInformation type = owningType.getProperty(propertyName);
TypeInformation<?> type = owningType.getProperty(propertyName);
if (type == null) {
throw new IllegalArgumentException(String.format(ERROR_TEMPLATE,
@ -72,7 +72,7 @@ public class Property { @@ -72,7 +72,7 @@ public class Property {
this.name = propertyName;
}
private TypeInformation getPropertyType(TypeInformation type) {
private TypeInformation<?> getPropertyType(TypeInformation<?> type) {
if (type.isCollectionLike()) {
return type.getComponentType();
@ -95,7 +95,7 @@ public class Property { @@ -95,7 +95,7 @@ public class Property {
* @param owningType
* @param toTraverse
*/
Property(String name, TypeInformation owningType, String toTraverse) {
Property(String name, TypeInformation<?> owningType, String toTraverse) {
this(name, owningType);
@ -224,10 +224,10 @@ public class Property { @@ -224,10 +224,10 @@ public class Property {
*/
public static Property from(String source, Class<?> type) {
return from(source, new ClassTypeInformation(type));
return from(source, ClassTypeInformation.from(type));
}
private static Property from(String source, TypeInformation type) {
private static Property from(String source, TypeInformation<?> type) {
Iterator<String> parts = Arrays.asList(source.split("_")).iterator();
@ -275,7 +275,7 @@ public class Property { @@ -275,7 +275,7 @@ public class Property {
* @param type
* @return
*/
private static Property create(String source, TypeInformation type) {
private static Property create(String source, TypeInformation<?> type) {
return create(source, type, "");
}
@ -292,7 +292,7 @@ public class Property { @@ -292,7 +292,7 @@ public class Property {
* @param addTail
* @return
*/
private static Property create(String source, TypeInformation type, String addTail) {
private static Property create(String source, TypeInformation<?> type, String addTail) {
IllegalArgumentException exception = null;

1
spring-data-commons-core/src/main/java/org/springframework/data/repository/support/DefaultRepositoryInformation.java

@ -35,6 +35,7 @@ import org.springframework.util.Assert; @@ -35,6 +35,7 @@ import org.springframework.util.Assert;
*/
class DefaultRepositoryInformation implements RepositoryInformation {
@SuppressWarnings("rawtypes")
private static final TypeVariable<Class<Repository>>[] PARAMETERS = Repository.class.getTypeParameters();
private static final String DOMAIN_TYPE_NAME = PARAMETERS[0].getName();
private static final String ID_TYPE_NAME = PARAMETERS[1].getName();

3
spring-data-commons-core/src/main/java/org/springframework/data/repository/util/ClassUtils.java

@ -22,11 +22,8 @@ import java.lang.reflect.Type; @@ -22,11 +22,8 @@ import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.domain.Page;
import org.springframework.data.repository.Repository;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

11
spring-data-commons-core/src/main/java/org/springframework/data/util/ArrayTypeDiscoverer.java

@ -9,7 +9,7 @@ import java.lang.reflect.Type; @@ -9,7 +9,7 @@ import java.lang.reflect.Type;
*
* @author Oliver Gierke
*/
public class ArrayTypeDiscoverer extends TypeDiscoverer {
public class ArrayTypeDiscoverer<S> extends TypeDiscoverer<S> {
private GenericArrayType type;
@ -18,7 +18,7 @@ public class ArrayTypeDiscoverer extends TypeDiscoverer { @@ -18,7 +18,7 @@ public class ArrayTypeDiscoverer extends TypeDiscoverer {
* @param parent
* @param parent
*/
protected ArrayTypeDiscoverer(GenericArrayType type, TypeDiscoverer parent) {
protected ArrayTypeDiscoverer(GenericArrayType type, TypeDiscoverer<?> parent) {
super(type, null, parent);
this.type = type;
}
@ -27,16 +27,17 @@ public class ArrayTypeDiscoverer extends TypeDiscoverer { @@ -27,16 +27,17 @@ public class ArrayTypeDiscoverer extends TypeDiscoverer {
* @see org.springframework.data.util.TypeDiscoverer#getType()
*/
@Override
public Class<?> getType() {
@SuppressWarnings("unchecked")
public Class<S> getType() {
return Array.newInstance(resolveType(type.getGenericComponentType()), 0).getClass();
return (Class<S>) Array.newInstance(resolveType(type.getGenericComponentType()), 0).getClass();
}
/* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
*/
@Override
public TypeInformation getComponentType() {
public TypeInformation<?> getComponentType() {
Type componentType = type.getGenericComponentType();
return createInfo(componentType);

23
spring-data-commons-core/src/main/java/org/springframework/data/util/ClassTypeInformation.java

@ -11,26 +11,30 @@ import org.springframework.util.Assert; @@ -11,26 +11,30 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
*/
public class ClassTypeInformation extends TypeDiscoverer {
public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
private final Class<?> type;
private final Class<S> type;
public static <S> TypeInformation<S> from(Class<S> type) {
return new ClassTypeInformation<S>(type);
}
/**
* Creates {@link ClassTypeInformation} for the given type.
*
* @param type
*/
public ClassTypeInformation(Class<?> type) {
public ClassTypeInformation(Class<S> type) {
this(type, GenericTypeResolver.getTypeVariableMap(type), null);
}
ClassTypeInformation(Class<?> type, TypeDiscoverer parent) {
ClassTypeInformation(Class<S> type, TypeDiscoverer<?> parent) {
this(type, null, parent);
}
@SuppressWarnings("rawtypes")
ClassTypeInformation(Class<?> type, Map<TypeVariable, Type> typeVariableMap,
TypeDiscoverer parent) {
ClassTypeInformation(Class<S> type, Map<TypeVariable, Type> typeVariableMap,
TypeDiscoverer<?> parent) {
super(type, typeVariableMap, parent);
this.type = type;
}
@ -41,7 +45,7 @@ public class ClassTypeInformation extends TypeDiscoverer { @@ -41,7 +45,7 @@ public class ClassTypeInformation extends TypeDiscoverer {
* @see org.springframework.data.document.mongodb.TypeDiscovererTest.FieldInformation#getType()
*/
@Override
public Class<?> getType() {
public Class<S> getType() {
return type;
}
@ -49,7 +53,8 @@ public class ClassTypeInformation extends TypeDiscoverer { @@ -49,7 +53,8 @@ public class ClassTypeInformation extends TypeDiscoverer {
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
*/
@Override
public TypeInformation getComponentType() {
@SuppressWarnings({ "rawtypes", "unchecked" })
public TypeInformation<?> getComponentType() {
if (type.isArray()) {
return createInfo(resolveArrayType(type));
@ -75,7 +80,7 @@ public class ClassTypeInformation extends TypeDiscoverer { @@ -75,7 +80,7 @@ public class ClassTypeInformation extends TypeDiscoverer {
return false;
}
ClassTypeInformation that = (ClassTypeInformation) obj;
ClassTypeInformation<?> that = (ClassTypeInformation<?>) obj;
return this.type.equals(that.type);
}

49
spring-data-commons-core/src/main/java/org/springframework/data/util/TypeDiscoverer.java

@ -1,11 +1,15 @@ @@ -1,11 +1,15 @@
package org.springframework.data.util;
import static org.springframework.util.ObjectUtils.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -18,13 +22,13 @@ import org.springframework.util.ReflectionUtils; @@ -18,13 +22,13 @@ import org.springframework.util.ReflectionUtils;
*
* @author Oliver Gierke
*/
class TypeDiscoverer implements TypeInformation {
class TypeDiscoverer<S> implements TypeInformation<S> {
private final Type type;
@SuppressWarnings("rawtypes")
private final Map<TypeVariable, Type> typeVariableMap;
private final Map<String, TypeInformation> fieldTypes = new ConcurrentHashMap<String, TypeInformation>();
private final TypeDiscoverer parent;
private final Map<String, TypeInformation<?>> fieldTypes = new ConcurrentHashMap<String, TypeInformation<?>>();
private final TypeDiscoverer<?> parent;
/**
* Creates a ne {@link TypeDiscoverer} for the given type, type variable map and parent.
@ -35,7 +39,7 @@ class TypeDiscoverer implements TypeInformation { @@ -35,7 +39,7 @@ class TypeDiscoverer implements TypeInformation {
*/
@SuppressWarnings("rawtypes")
protected TypeDiscoverer(Type type, Map<TypeVariable, Type> typeVariableMap,
TypeDiscoverer parent) {
TypeDiscoverer<?> parent) {
Assert.notNull(type);
this.type = type;
@ -61,7 +65,8 @@ class TypeDiscoverer implements TypeInformation { @@ -61,7 +65,8 @@ class TypeDiscoverer implements TypeInformation {
* @param fieldType
* @return
*/
protected TypeInformation createInfo(Type fieldType) {
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TypeInformation<?> createInfo(Type fieldType) {
if (fieldType.equals(this.type)) {
return this;
@ -94,10 +99,26 @@ class TypeDiscoverer implements TypeInformation { @@ -94,10 +99,26 @@ class TypeDiscoverer implements TypeInformation {
* @param type
* @return
*/
protected Class<?> resolveType(Type type) {
@SuppressWarnings("unchecked")
protected Class<S> resolveType(Type type) {
return GenericTypeResolver.resolveType(type, getTypeVariableMap());
}
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeInformation#getParameterTypes(java.lang.reflect.Constructor)
*/
public List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor) {
List<TypeInformation<?>> result = new ArrayList<TypeInformation<?>>();
for (Class<?> type : constructor.getParameterTypes()) {
result.add(createInfo(type));
}
return result;
}
/*
* (non-Javadoc)
@ -106,7 +127,7 @@ class TypeDiscoverer implements TypeInformation { @@ -106,7 +127,7 @@ class TypeDiscoverer implements TypeInformation {
* org.springframework.data.document.mongodb.TypeDiscovererTest.FieldInformation
* #getField(java.lang.String)
*/
public TypeInformation getProperty(String fieldname) {
public TypeInformation<?> getProperty(String fieldname) {
int separatorIndex = fieldname.indexOf(".");
@ -115,7 +136,7 @@ class TypeDiscoverer implements TypeInformation { @@ -115,7 +136,7 @@ class TypeDiscoverer implements TypeInformation {
return fieldTypes.get(fieldname);
}
TypeInformation propertyInformation = getPropertyInformation(fieldname);
TypeInformation<?> propertyInformation = getPropertyInformation(fieldname);
if (propertyInformation != null) {
fieldTypes.put(fieldname, propertyInformation);
}
@ -123,11 +144,11 @@ class TypeDiscoverer implements TypeInformation { @@ -123,11 +144,11 @@ class TypeDiscoverer implements TypeInformation {
}
String head = fieldname.substring(0, separatorIndex);
TypeInformation info = fieldTypes.get(head);
TypeInformation<?> info = fieldTypes.get(head);
return info.getProperty(fieldname.substring(separatorIndex + 1));
}
private TypeInformation getPropertyInformation(String fieldname) {
private TypeInformation<?> getPropertyInformation(String fieldname) {
Field field = ReflectionUtils.findField(getType(), fieldname);
@ -145,7 +166,7 @@ class TypeDiscoverer implements TypeInformation { @@ -145,7 +166,7 @@ class TypeDiscoverer implements TypeInformation {
* org.springframework.data.document.mongodb.TypeDiscovererTest.FieldInformation
* #getType()
*/
public Class<?> getType() {
public Class<S> getType() {
return resolveType(type);
}
@ -160,7 +181,7 @@ class TypeDiscoverer implements TypeInformation { @@ -160,7 +181,7 @@ class TypeDiscoverer implements TypeInformation {
/* (non-Javadoc)
* @see org.springframework.data.util.TypeInformation#getMapValueType()
*/
public TypeInformation getMapValueType() {
public TypeInformation<?> getMapValueType() {
if (!Map.class.isAssignableFrom(getType())) {
return null;
@ -182,7 +203,7 @@ class TypeDiscoverer implements TypeInformation { @@ -182,7 +203,7 @@ class TypeDiscoverer implements TypeInformation {
/* (non-Javadoc)
* @see org.springframework.data.util.TypeInformation#getComponentType()
*/
public TypeInformation getComponentType() {
public TypeInformation<?> getComponentType() {
if (!(Map.class.isAssignableFrom(getType()) || isCollectionLike())) {
return null;
@ -211,7 +232,7 @@ class TypeDiscoverer implements TypeInformation { @@ -211,7 +232,7 @@ class TypeDiscoverer implements TypeInformation {
return false;
}
TypeDiscoverer that = (TypeDiscoverer) obj;
TypeDiscoverer<?> that = (TypeDiscoverer<?>) obj;
boolean typeEqual = nullSafeEquals(this.type, that.type);
boolean typeVariableMapEqual = nullSafeEquals(this.typeVariableMap,

14
spring-data-commons-core/src/main/java/org/springframework/data/util/TypeInformation.java

@ -1,7 +1,9 @@ @@ -1,7 +1,9 @@
package org.springframework.data.util;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@ -11,7 +13,9 @@ import java.util.Map; @@ -11,7 +13,9 @@ import java.util.Map;
*
* @author Oliver Gierke
*/
public interface TypeInformation {
public interface TypeInformation<S> {
List<TypeInformation<?>> getParameterTypes(Constructor<?> constructor);
/**
* Returns the property information for the property with the given name.
@ -20,7 +24,7 @@ public interface TypeInformation { @@ -20,7 +24,7 @@ public interface TypeInformation {
* @param fieldname
* @return
*/
TypeInformation getProperty(String fieldname);
TypeInformation<?> getProperty(String fieldname);
/**
* Returns whether the type can be considered a collection, which means it's a container of elements, e.g. a
@ -36,7 +40,7 @@ public interface TypeInformation { @@ -36,7 +40,7 @@ public interface TypeInformation {
*
* @return
*/
TypeInformation getComponentType();
TypeInformation<?> getComponentType();
/**
* Returns whether the property is a {@link Map}. If this returns {@literal true} you can expect
@ -51,7 +55,7 @@ public interface TypeInformation { @@ -51,7 +55,7 @@ public interface TypeInformation {
*
* @return
*/
TypeInformation getMapValueType();
TypeInformation<?> getMapValueType();
/**
* Returns the type of the property. Will resolve generics and the generic
@ -59,5 +63,5 @@ public interface TypeInformation { @@ -59,5 +63,5 @@ public interface TypeInformation {
*
* @return
*/
Class<?> getType();
Class<S> getType();
}

8
spring-data-commons-core/src/main/java/org/springframework/data/util/TypeVariableTypeInformation.java

@ -13,7 +13,7 @@ import org.springframework.util.Assert; @@ -13,7 +13,7 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
*/
class TypeVariableTypeInformation extends TypeDiscoverer {
class TypeVariableTypeInformation<T> extends TypeDiscoverer<T> {
private final TypeVariable<?> variable;
private final Type owningType;
@ -26,7 +26,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer { @@ -26,7 +26,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer {
* @param owningType must not be {@literal null}
* @param parent
*/
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer parent) {
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent) {
super(variable, null, parent);
Assert.notNull(variable);
@ -40,7 +40,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer { @@ -40,7 +40,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer {
* @see org.springframework.data.document.mongodb.TypeDiscovererTest.TypeDiscoverer#getType()
*/
@Override
public Class<?> getType() {
public Class<T> getType() {
int index = getIndex(variable);
@ -82,7 +82,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer { @@ -82,7 +82,7 @@ class TypeVariableTypeInformation extends TypeDiscoverer {
return false;
}
TypeVariableTypeInformation that = (TypeVariableTypeInformation) obj;
TypeVariableTypeInformation<?> that = (TypeVariableTypeInformation<?>) obj;
return nullSafeEquals(this.owningType, that.owningType)
&& nullSafeEquals(this.variable, that.variable);
}

58
spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java

@ -16,47 +16,81 @@ @@ -16,47 +16,81 @@
package org.springframework.data.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.PersistentEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.data.mapping.model.PersistentProperty;
import org.springframework.data.util.TypeInformation;
import static org.junit.Assert.*;
/**
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:mapping.xml")
public class MappingMetadataTests {
BasicMappingContext ctx;
SampleMappingContext ctx;
@Before
public void setup() {
ctx = new BasicMappingContext();
ctx = new SampleMappingContext();
}
@Test
public void testPojoWithId() {
PersistentEntity<?> person = ctx.addPersistentEntity(PersonWithId.class);
PersistentEntity<?, SampleProperty> person = ctx.addPersistentEntity(PersonWithId.class);
assertNotNull(person.getIdProperty());
assertEquals(String.class, person.getIdProperty().getType());
}
@Test
public void testAssociations() {
PersistentEntity<?> person = ctx.addPersistentEntity(PersonWithChildren.class);
PersistentEntity<?, SampleProperty> person = ctx.addPersistentEntity(PersonWithChildren.class);
assertNotNull(person.getAssociations());
for (Association association : person.getAssociations()) {
for (Association<SampleProperty> association : person.getAssociations()) {
assertEquals(Child.class, association.getInverse().getComponentType());
}
}
public interface SampleProperty extends PersistentProperty<SampleProperty> {
}
public class SampleMappingContext extends AbstractMappingContext<MutablePersistentEntity<?, SampleProperty>, SampleProperty> {
@Override
protected <T> MutablePersistentEntity<?, SampleProperty> createPersistentEntity(
TypeInformation<T> typeInformation) {
return new BasicPersistentEntity<T, MappingMetadataTests.SampleProperty>(typeInformation);
}
@Override
protected SampleProperty createPersistentProperty(Field field,
PropertyDescriptor descriptor,
MutablePersistentEntity<?, SampleProperty> owner) {
return new SamplePropertyImpl(field, descriptor, owner);
}
}
public class SamplePropertyImpl extends AnnotationBasedPersistentProperty<SampleProperty> implements SampleProperty {
public SamplePropertyImpl(Field field,
PropertyDescriptor propertyDescriptor,
PersistentEntity<?, SampleProperty> owner) {
super(field, propertyDescriptor, owner);
}
@Override
protected Association<SampleProperty> createAssociation() {
return new Association<MappingMetadataTests.SampleProperty>(this, null);
}
}
}

2
spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java

@ -27,7 +27,7 @@ import java.util.List; @@ -27,7 +27,7 @@ import java.util.List;
public class PersonWithChildren extends Person {
@Id
private String id;
String id;
@Reference
private List<Child> children;

133
spring-data-commons-core/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java

@ -0,0 +1,133 @@ @@ -0,0 +1,133 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mapping.model.PreferredConstructor;
import org.springframework.data.mapping.model.PreferredConstructor.Parameter;
/**
* Unit tests for {@link PreferredConstructorDiscoverer}.
*
* @author Oliver Gierke
*/
public class PreferredConstructorDiscovererUnitTests {
@Test
public void findsNoArgConstructorForClassWithoutExplicitConstructor() {
PreferredConstructorDiscoverer<EntityWithoutConstructor> discoverer =
new PreferredConstructorDiscoverer<EntityWithoutConstructor>(
EntityWithoutConstructor.class);
PreferredConstructor<EntityWithoutConstructor> constructor =
discoverer.getConstructor();
assertThat(constructor, is(notNullValue()));
assertThat(constructor.isNoArgConstructor(), is(true));
assertThat(constructor.isExplicitlyAnnotated(), is(false));
}
@Test
public void findsNoArgConstructorForClassWithMultipleConstructorsAndNoArgOne() {
PreferredConstructorDiscoverer<ClassWithEmptyConstructor> discoverer =
new PreferredConstructorDiscoverer<ClassWithEmptyConstructor>(
ClassWithEmptyConstructor.class);
PreferredConstructor<ClassWithEmptyConstructor> constructor =
discoverer.getConstructor();
assertThat(constructor, is(notNullValue()));
assertThat(constructor.isNoArgConstructor(), is(true));
assertThat(constructor.isExplicitlyAnnotated(), is(false));
}
@Test(expected=IllegalArgumentException.class)
public void throwsExceptionForMultipleConstructorsAndNoNoArgConstructorWithoutAnnotation() {
new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsWithoutEmptyOne>(
ClassWithMultipleConstructorsWithoutEmptyOne.class);
}
@Test
public void usesConstructorWithAnnotationOverEveryOther() {
PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation> discoverer =
new PreferredConstructorDiscoverer<ClassWithMultipleConstructorsAndAnnotation>(
ClassWithMultipleConstructorsAndAnnotation.class);
PreferredConstructor<ClassWithMultipleConstructorsAndAnnotation> constructor =
discoverer.getConstructor();
assertThat(constructor, is(notNullValue()));
assertThat(constructor.isNoArgConstructor(), is(false));
assertThat(constructor.isExplicitlyAnnotated(), is(true));
List<Parameter<?>> parameters = constructor.getParameters();
assertThat(parameters.size(), is(1));
assertThat(parameters.get(0).getType().getType(), typeCompatibleWith(Long.class));
}
static class EntityWithoutConstructor {
}
static class ClassWithEmptyConstructor {
public ClassWithEmptyConstructor() {
}
}
static class ClassWithMultipleConstructorsAndEmptyOne {
public ClassWithMultipleConstructorsAndEmptyOne(String value) {
}
public ClassWithMultipleConstructorsAndEmptyOne() {
}
}
static class ClassWithMultipleConstructorsWithoutEmptyOne {
public ClassWithMultipleConstructorsWithoutEmptyOne(String value) {
}
public ClassWithMultipleConstructorsWithoutEmptyOne(Long value) {
}
}
static class ClassWithMultipleConstructorsAndAnnotation {
public ClassWithMultipleConstructorsAndAnnotation() {
}
public ClassWithMultipleConstructorsAndAnnotation(String value) {
}
@PersistenceConstructor
public ClassWithMultipleConstructorsAndAnnotation(Long value) {
}
}
}

1
spring-data-commons-core/src/test/java/org/springframework/data/repository/util/ClassUtilsUnitTests.java

@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
*/
package org.springframework.data.repository.util;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.repository.util.ClassUtils.*;

66
spring-data-commons-core/src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

@ -12,6 +12,8 @@ import org.junit.Test; @@ -12,6 +12,8 @@ import org.junit.Test;
import org.springframework.data.mapping.Person;
/**
* Unit tests for {@link ClassTypeInformation}.
*
* @author Oliver Gierke
*/
public class ClassTypeInformationUnitTests {
@ -19,10 +21,9 @@ public class ClassTypeInformationUnitTests { @@ -19,10 +21,9 @@ public class ClassTypeInformationUnitTests {
@Test
public void discoversTypeForSimpleGenericField() {
TypeInformation discoverer = new ClassTypeInformation(
ConcreteType.class);
TypeInformation<ConcreteType> discoverer = ClassTypeInformation.from(ConcreteType.class);
assertEquals(ConcreteType.class, discoverer.getType());
TypeInformation content = discoverer.getProperty("content");
TypeInformation<?> content = discoverer.getProperty("content");
assertEquals(String.class, content.getType());
assertNull(content.getComponentType());
assertNull(content.getMapValueType());
@ -31,12 +32,11 @@ public class ClassTypeInformationUnitTests { @@ -31,12 +32,11 @@ public class ClassTypeInformationUnitTests {
@Test
public void discoversTypeForNestedGenericField() {
TypeInformation discoverer = new ClassTypeInformation(
ConcreteWrapper.class);
TypeInformation<ConcreteWrapper> discoverer = ClassTypeInformation.from(ConcreteWrapper.class);
assertEquals(ConcreteWrapper.class, discoverer.getType());
TypeInformation wrapper = discoverer.getProperty("wrapped");
TypeInformation<?> wrapper = discoverer.getProperty("wrapped");
assertEquals(GenericType.class, wrapper.getType());
TypeInformation content = wrapper.getProperty("content");
TypeInformation<?> content = wrapper.getProperty("content");
assertEquals(String.class, content.getType());
assertEquals(String.class,
@ -46,9 +46,10 @@ public class ClassTypeInformationUnitTests { @@ -46,9 +46,10 @@ public class ClassTypeInformationUnitTests {
}
@Test
@SuppressWarnings("rawtypes")
public void discoversBoundType() {
ClassTypeInformation information = new ClassTypeInformation(
TypeInformation<GenericTypeWithBound> information = ClassTypeInformation.from(
GenericTypeWithBound.class);
assertEquals(Person.class, information.getProperty("person").getType());
}
@ -56,16 +57,17 @@ public class ClassTypeInformationUnitTests { @@ -56,16 +57,17 @@ public class ClassTypeInformationUnitTests {
@Test
public void discoversBoundTypeForSpecialization() {
ClassTypeInformation information = new ClassTypeInformation(
TypeInformation<SpecialGenericTypeWithBound> information = ClassTypeInformation.from(
SpecialGenericTypeWithBound.class);
assertEquals(SpecialPerson.class, information.getProperty("person")
.getType());
}
@Test
@SuppressWarnings("rawtypes")
public void discoversBoundTypeForNested() {
ClassTypeInformation information = new ClassTypeInformation(
TypeInformation<AnotherGenericType> information = ClassTypeInformation.from(
AnotherGenericType.class);
assertEquals(GenericTypeWithBound.class, information.getProperty("nested")
.getType());
@ -75,9 +77,9 @@ public class ClassTypeInformationUnitTests { @@ -75,9 +77,9 @@ public class ClassTypeInformationUnitTests {
@Test
public void discoversArraysAndCollections() {
ClassTypeInformation information = new ClassTypeInformation(StringCollectionContainer.class);
TypeInformation<StringCollectionContainer> information = ClassTypeInformation.from(StringCollectionContainer.class);
TypeInformation property = information.getProperty("array");
TypeInformation<?> property = information.getProperty("array");
assertEquals(property.getComponentType().getType(), String.class);
Class<?> type = property.getType();
@ -98,32 +100,31 @@ public class ClassTypeInformationUnitTests { @@ -98,32 +100,31 @@ public class ClassTypeInformationUnitTests {
@Test
public void discoversMapValueType() {
ClassTypeInformation information = new ClassTypeInformation(StringMapContainer.class);
TypeInformation genericMap = information.getProperty("genericMap");
TypeInformation<StringMapContainer> information = ClassTypeInformation.from(StringMapContainer.class);
TypeInformation<?> genericMap = information.getProperty("genericMap");
assertEquals(Map.class, genericMap.getType());
assertEquals(String.class, genericMap.getMapValueType().getType());
TypeInformation map = information.getProperty("map");
TypeInformation<?> map = information.getProperty("map");
assertEquals(Map.class, map.getType());
assertEquals(Calendar.class, map.getMapValueType().getType());
}
private class StringMapContainer extends MapContainer<String> {
static class StringMapContainer extends MapContainer<String> {
}
@SuppressWarnings("unused")
private class MapContainer<T> {
static class MapContainer<T> {
Map<String, T> genericMap;
Map<String, Calendar> map;
}
private class StringCollectionContainer extends CollectionContainer<String> {
static class StringCollectionContainer extends CollectionContainer<String> {
}
@SuppressWarnings({"unused", "rawtypes"})
private class CollectionContainer<T> {
@SuppressWarnings("rawtypes")
static class CollectionContainer<T> {
T[] array;
Collection<T>[] foo;
@ -131,48 +132,43 @@ public class ClassTypeInformationUnitTests { @@ -131,48 +132,43 @@ public class ClassTypeInformationUnitTests {
Set rawSet;
}
@SuppressWarnings("unused")
private class GenericTypeWithBound<T extends Person> {
static class GenericTypeWithBound<T extends Person> {
T person;
}
@SuppressWarnings("unused")
private class AnotherGenericType<T extends Person, S extends GenericTypeWithBound<T>> {
static class AnotherGenericType<T extends Person, S extends GenericTypeWithBound<T>> {
S nested;
}
private class SpecialGenericTypeWithBound extends
static class SpecialGenericTypeWithBound extends
GenericTypeWithBound<SpecialPerson> {
}
private abstract class SpecialPerson extends Person {
static abstract class SpecialPerson extends Person {
protected SpecialPerson(Integer ssn, String firstName, String lastName) {
super(ssn, firstName, lastName);
}
}
@SuppressWarnings("unused")
private class GenericType<T, S> {
static class GenericType<T, S> {
Long index;
T content;
}
private class ConcreteType extends GenericType<String, Object> {
static class ConcreteType extends GenericType<String, Object> {
}
@SuppressWarnings("unused")
private class GenericWrapper<S> {
static class GenericWrapper<S> {
GenericType<S, Object> wrapped;
}
private class ConcreteWrapper extends GenericWrapper<String> {
static class ConcreteWrapper extends GenericWrapper<String> {
}
}

2
spring-data-commons-core/src/test/java/org/springframework/data/util/TypeDiscovererUnitTests.java

@ -11,6 +11,6 @@ public class TypeDiscovererUnitTests { @@ -11,6 +11,6 @@ public class TypeDiscovererUnitTests {
@Test(expected = IllegalArgumentException.class)
public void rejectsNullType() {
new TypeDiscoverer(null, null, null);
new TypeDiscoverer<Object>(null, null, null);
}
}

Loading…
Cancel
Save