diff --git a/pom.xml b/pom.xml index 9001e043d4..c0787b50ca 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-commons - 2.6.0-SNAPSHOT + 2.6.0-GH-2408-2409-SNAPSHOT Spring Data Core diff --git a/src/main/java/org/springframework/data/mapping/PersistentProperty.java b/src/main/java/org/springframework/data/mapping/PersistentProperty.java index 150ba628fd..acffe7cd24 100644 --- a/src/main/java/org/springframework/data/mapping/PersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/PersistentProperty.java @@ -70,9 +70,21 @@ public interface PersistentProperty

> { * {@link Map}'s value type transparently. * * @return + * @deprecated since 2.6 for removal in 3.0. Use {@link #getPersistentEntityTypeInformation()} instead. */ + @Deprecated Iterable> getPersistentEntityTypes(); + /** + * 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 + * @since 2.6 + */ + Iterable> getPersistentEntityTypeInformation(); + /** * Returns the getter method to access the property value if available. Might return {@literal null} in case there is * no getter method with a return type assignable to the actual property's type. @@ -395,6 +407,19 @@ default boolean hasActualTypeAnnotation(Class annotationTy @Nullable Class getAssociationTargetType(); + /** + * Return the type the property refers to in case it's an association, i.e. {@link #isAssociation()} returns + * {@literal true}. That means, that implementations must return a non-{@literal null} value from this method + * in that case. We also recommend to return {@literal null} for non-associations right away to establish symmetry + * between this method and {@link #isAssociation()}. + * + * @return the type the property refers to in case it's an association, i.e. {@link #isAssociation()} returns + * {@literal true}. + * @since 2.6 + */ + @Nullable + TypeInformation getAssociationTargetTypeInformation(); + /** * Returns a {@link PersistentPropertyAccessor} for the current property's owning value. * diff --git a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java index 6bd3935411..04c5c21d6d 100644 --- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java +++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java @@ -33,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; @@ -576,7 +575,7 @@ private void createAndRegisterProperty(Property input) { return; } - property.getPersistentEntityTypes().forEach(it -> { + property.getPersistentEntityTypeInformation().forEach(it -> { if (shouldCreatePersistentEntityFor(it)) { addPersistentEntity(it); diff --git a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java index fb30c1387f..b7361896b5 100644 --- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java @@ -164,6 +164,15 @@ public TypeInformation getTypeInformation() { */ @Override public Iterable> getPersistentEntityTypes() { + return getPersistentEntityTypeInformation(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityTypeInformation() + */ + @Override + public Iterable> getPersistentEntityTypeInformation() { if (isMap() || isCollectionLike()) { return entityTypeInformation.get(); @@ -279,11 +288,21 @@ public Association

getAssociation() { @Override public Class getAssociationTargetType() { - TypeInformation result = associationTargetType.getNullable(); + TypeInformation result = getAssociationTargetTypeInformation(); return result != null ? result.getType() : null; } + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.PersistentProperty#getAssociationTargetTypeInformation() + */ + @Nullable + @Override + public TypeInformation getAssociationTargetTypeInformation() { + return associationTargetType.getNullable(); + } + /* * (non-Javadoc) * @see org.springframework.data.mapping.PersistentProperty#isCollectionLike() @@ -356,11 +375,7 @@ public Class getMapValueType() { */ @Override public Class getActualType() { - - TypeInformation targetType = associationTargetType.getNullable(); - TypeInformation result = targetType == null ? information.getRequiredActualType() : targetType; - - return result.getType(); + return getActualTypeInformation().getType(); } /* @@ -375,6 +390,12 @@ protected Property getProperty() { return this.property; } + protected TypeInformation getActualTypeInformation() { + + TypeInformation targetType = associationTargetType.getNullable(); + return targetType == null ? information.getRequiredActualType() : targetType; + } + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) @@ -415,9 +436,8 @@ public String toString() { private Set> detectEntityTypes(SimpleTypeHolder simpleTypes) { - TypeInformation typeToStartWith = ASSOCIATION_TYPE != null && ASSOCIATION_TYPE.isAssignableFrom(rawType) - ? information.getComponentType() - : information; + TypeInformation typeToStartWith = getAssociationTargetTypeInformation(); + typeToStartWith = typeToStartWith == null ? information : typeToStartWith; Set> result = detectEntityTypes(typeToStartWith); diff --git a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java index 52e5392ee3..2be9853779 100644 --- a/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java +++ b/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java @@ -37,9 +37,11 @@ import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.Lazy; import org.springframework.data.util.Optionals; import org.springframework.data.util.StreamUtils; +import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -74,7 +76,7 @@ public abstract class AnnotationBasedPersistentProperty

isId = Lazy.of(() -> isAnnotationPresent(Id.class)); private final Lazy isVersion = Lazy.of(() -> isAnnotationPresent(Version.class)); - private final Lazy> associationTargetType = Lazy.of(() -> { + private final Lazy> associationTargetType = Lazy.of(() -> { if (!isAssociation()) { return null; @@ -83,8 +85,8 @@ public abstract class AnnotationBasedPersistentProperty

!Class.class.equals(it) ? it : getActualType()) // - .orElseGet(() -> super.getAssociationTargetType()); + .map(it -> !Class.class.equals(it) ? ClassTypeInformation.from(it) : getActualTypeInformation()) // + .orElseGet(() -> super.getAssociationTargetTypeInformation()); }); /** @@ -295,11 +297,11 @@ public boolean usePropertyAccess() { /* * (non-Javadoc) - * @see org.springframework.data.mapping.PersistentProperty#getAssociationTargetType() + * @see org.springframework.data.mapping.model.AbstractPersistentProperty#getAssociationTargetTypeInformation() */ @Nullable @Override - public Class getAssociationTargetType() { + public TypeInformation getAssociationTargetTypeInformation() { return associationTargetType.getNullable(); } diff --git a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java index aa0e18b3b0..61967c2a76 100755 --- a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java +++ b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextIntegrationTests.java @@ -113,7 +113,7 @@ protected T createPersistentProperty(Property property, BasicPersistentEntity it.getType()) .containsExactly((Class) JMoleculesAggregate.class); } diff --git a/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java index fa6dbe8e95..7b4a52a677 100755 --- a/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/AnnotationBasedPersistentPropertyUnitTests.java @@ -47,6 +47,7 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.lang.Nullable; import org.springframework.test.util.ReflectionTestUtils; @@ -318,6 +319,16 @@ void detectsJMoleculesAssociation() { assertThat(property.getAssociationTargetType()).isEqualTo(JMoleculesAggregate.class); } + @Test // GH-2409 + void exposesAssociationTargetClassAsPersistentEntityType() { + + SamplePersistentProperty property = getProperty(WithReferences.class, "toSample"); + + assertThat(property.getPersistentEntityTypeInformation()) // + .isNotEmpty() // + .allMatch(it -> it.equals(ClassTypeInformation.from(Sample.class))); + } + @SuppressWarnings("unchecked") private Map, Annotation> getAnnotationCache(SamplePersistentProperty property) { return (Map, Annotation>) ReflectionTestUtils.getField(property, "annotationCache");