diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PersistentProperty.java index c3c5980cf..1f0f4c293 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -2,6 +2,8 @@ package org.springframework.data.mapping; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Map; import org.springframework.data.util.TypeInformation; @@ -30,39 +32,79 @@ public interface PersistentProperty

> { TypeInformation getTypeInformation(); + /** + * Returns the {@link TypeInformation} if the property references a {@link PersistentEntity}. Will return + * {@literal null} in case it refers to a simple type. Will return {@link Collection}'s component type or the + * {@link Map}'s value type transparently. + * + * @return + */ + Iterable> getPersistentEntityType(); + + /** + * Returns the {@link PropertyDescriptor} backing the {@link PersistentProperty}. + * + * @return + */ PropertyDescriptor getPropertyDescriptor(); Field getField(); String getSpelExpression(); - boolean isTransient(); - - boolean isAssociation(); - Association

getAssociation(); - boolean isCollection(); - - boolean isMap(); - - boolean isArray(); - - boolean isComplexType(); - /** - * Returns whether the property has to be regarded as entity which means its type will be also be considered to be a - * {@link PersistentEntity}. + * Returns whether the property is the ID property of the owning {@link PersistentEntity}. * * @return */ - boolean isEntity(); + boolean isIdProperty(); + + /** + * Returns whether the property is a {@link Collection}, {@link Iterable} or an array. + * + * @return + */ + boolean isCollectionLike(); /** - * Returns the component type of the type if it is a {@link java.util.Collection}. Will return the type of the key if the - * property is a {@link java.util.Map}. + * Returns whether the property is a {@link Map}. * - * @return the component type, the map's key type or {@literal null} if neither {@link java.util.Collection} nor {@link java.util.Map}. + * @return + */ + boolean isMap(); + + /** + * Returns whether the property is an array. + * + * @return + */ + boolean isArray(); + + /** + * Returns whether the property is transient. + * + * @return + */ + boolean isTransient(); + + + boolean shallBePersisted(); + + /** + * Returns whether the property is an {@link Association}. + * + * @return + */ + boolean isAssociation(); + + /** + * Returns the component type of the type if it is a {@link java.util.Collection}. Will return the type of the key if + * the property is a {@link java.util.Map}. + * + * @return the component type, the map's key type or {@literal null} if neither {@link java.util.Collection} nor + * {@link java.util.Map}. */ Class getComponentType(); @@ -80,5 +122,4 @@ public interface PersistentProperty

> { */ Class getMapValueType(); - boolean isIdProperty(); } diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index d950a98f5..ebba36525 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -69,7 +69,7 @@ public abstract class AbstractMappingContext, E> persistentEntities = new ConcurrentHashMap, E>(); private final ConcurrentMap> validators = new ConcurrentHashMap>(); - private final List> customSimpleTypes = new ArrayList>(); + private ApplicationEventPublisher applicationEventPublisher; private Set> initialEntitySet = new HashSet>(); private boolean strict = false; @@ -173,22 +173,23 @@ public abstract class AbstractMappingContext result = new ArrayList

(); E current = getPersistentEntity(propertyPath.getOwningType()); - + for (PropertyPath segment : propertyPath) { - + P persistentProperty = current.getPersistentProperty(segment.getSegment()); if (persistentProperty == null) { - throw new IllegalArgumentException(String.format("No property %s found on %s!", segment.getSegment(), current.getName())); + throw new IllegalArgumentException(String.format("No property %s found on %s!", segment.getSegment(), + current.getName())); } - + result.add(persistentProperty); - + if (segment.hasNext()) { current = getPersistentEntity(segment.getType()); } } - + return new DefaultPersistentPropertyPath

(result); } @@ -243,11 +244,12 @@ public abstract class AbstractMappingContext getNestedTypeToAdd(P property, PersistentEntity entity) { - - if (entity.getType().equals(property.getRawType())) { - return null; - } - - TypeInformation typeInformation = property.getTypeInformation(); - - if (customSimpleTypes.contains(typeInformation.getType())) { - return null; - } - - if (property.isEntity()) { - return typeInformation; - } - - if (property.isCollection()) { - return getTypeInformationIfNotSimpleType(getComponentTypeRecursively(typeInformation)); - } - - if (property.isMap()) { - return getTypeInformationIfNotSimpleType(typeInformation.getMapValueType()); - } - - return null; - } - private TypeInformation getComponentTypeRecursively(TypeInformation typeInformation) { TypeInformation componentType = typeInformation.getComponentType(); @@ -312,10 +277,6 @@ public abstract class AbstractMappingContext getTypeInformationIfNotSimpleType(TypeInformation information) { - return information == null || simpleTypeHolder.isSimpleType(information.getType()) ? null : information; - } - /** * Creates the concrete {@link PersistentEntity} instance. * @@ -336,7 +297,7 @@ public abstract class AbstractMappingContext descriptors; @@ -390,9 +351,12 @@ public abstract class AbstractMappingContext nestedType = getNestedTypeToAdd(property, entity); - if (nestedType != null) { - addPersistentEntity(nestedType); + if (entity.getType().equals(property.getRawType())) { + return; + } + + for (TypeInformation candidate : property.getPersistentEntityType()) { + addPersistentEntity(candidate); } } } diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java index 208b6e61f..4457fca15 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java @@ -20,7 +20,8 @@ import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.Collection; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import org.springframework.data.annotation.Reference; @@ -86,6 +87,34 @@ public abstract class AbstractPersistentProperty

return information; } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityType() + */ + public Iterable> getPersistentEntityType() { + + List> result = new ArrayList>(); + + TypeInformation type = getTypeInformation(); + + if (isEntity()) { + result.add(type); + } + + if (type.isCollectionLike() || isMap()) { + TypeInformation nestedType = getTypeInformationIfNotSimpleType(getTypeInformation().getActualType()); + if (nestedType != null) { + result.add(nestedType); + } + } + + return result; + } + + private TypeInformation getTypeInformationIfNotSimpleType(TypeInformation information) { + return information == null || simpleTypeHolder.isSimpleType(information.getType()) ? null : information; + } + public PropertyDescriptor getPropertyDescriptor() { return propertyDescriptor; } @@ -102,6 +131,14 @@ public abstract class AbstractPersistentProperty

return Modifier.isTransient(field.getModifiers()); } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#shallBePersisted() + */ + public boolean shallBePersisted() { + return !isTransient(); + } + public boolean isAssociation() { if (field.isAnnotationPresent(Reference.class)) { return true; @@ -119,8 +156,12 @@ public abstract class AbstractPersistentProperty

return association; } - public boolean isCollection() { - return Collection.class.isAssignableFrom(getType()) || isArray(); + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#isCollectionLike() + */ + public boolean isCollectionLike() { + return information.isCollectionLike(); } public boolean isMap() { @@ -134,21 +175,19 @@ public abstract class AbstractPersistentProperty

return getType().isArray(); } - public boolean isComplexType() { - if (isCollection() || isArray()) { - return !simpleTypeHolder.isSimpleType(getComponentType()); - } else { - return !simpleTypeHolder.isSimpleType(getType()); - } - } - - public boolean isEntity() { - return isComplexType() && !isTransient() && !isCollection() && !isMap(); + protected boolean isEntity() { + + boolean isComplexType = !simpleTypeHolder.isSimpleType(information.getActualType().getType()); + return isComplexType && !isTransient() && !isCollectionLike() && !isMap(); } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#getComponentType() + */ public Class getComponentType() { - if (!isMap() && !isCollection()) { + if (!isMap() && !isCollectionLike()) { return null; } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/model/AbstractPersistentPropertyUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/model/AbstractPersistentPropertyUnitTests.java index 3525d9f9e..1049b1e65 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/model/AbstractPersistentPropertyUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/model/AbstractPersistentPropertyUnitTests.java @@ -1,13 +1,18 @@ package org.springframework.data.mapping.model; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.util.TreeSet; +import org.junit.Before; import org.junit.Test; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; import org.springframework.util.ReflectionUtils; /** @@ -16,23 +21,40 @@ import org.springframework.util.ReflectionUtils; * @author Oliver Gierke */ public class AbstractPersistentPropertyUnitTests { + + TypeInformation typeInfo; + PersistentEntity entity; + SimpleTypeHolder typeHolder; + + @Before + public void setUp() { + typeInfo = ClassTypeInformation.from(TestClassComplex.class); + entity = new BasicPersistentEntity(typeInfo); + typeHolder = new SimpleTypeHolder(); + } + /** * @see DATACMNS-68 - * @throws Exception */ @Test public void discoversComponentTypeCorrectly() throws Exception { - BasicPersistentEntity entity = new BasicPersistentEntity( - ClassTypeInformation.from(TestClassComplex.class)); - Field field = ReflectionUtils.findField(TestClassComplex.class, "testClassSet"); - SamplePersistentProperty property = new SamplePersistentProperty(field, null, entity, new SimpleTypeHolder()); + SamplePersistentProperty property = new SamplePersistentProperty(field, null, entity, typeHolder); property.getComponentType(); } + @Test + public void returnsNestedEntityTypeCorrectly() { + + Field field = ReflectionUtils.findField(TestClassComplex.class, "testClassSet"); + + SamplePersistentProperty property = new SamplePersistentProperty(field, null, entity, typeHolder); + assertThat(property.getPersistentEntityType().iterator().hasNext(), is(false)); + } + @SuppressWarnings("serial") class TestClassSet extends TreeSet { }