Skip to content

Fixes for #2408 and #2409. #2410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.6.0-SNAPSHOT</version>
<version>2.6.0-GH-2408-2409-SNAPSHOT</version>

<name>Spring Data Core</name>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,21 @@ public interface PersistentProperty<P extends PersistentProperty<P>> {
* {@link Map}'s value type transparently.
*
* @return
* @deprecated since 2.6 for removal in 3.0. Use {@link #getPersistentEntityTypeInformation()} instead.
*/
@Deprecated
Iterable<? extends TypeInformation<?>> 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<? extends TypeInformation<?>> getPersistentEntityTypeInformation();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation is a bit confusing as it states the method to return null for a method thats return type is an Iterable. Wouldn't empty be a better fit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Indeed, the Javadoc still stems from the times that the original method which the comment was copied from returned a single type, not a collection.

/**
* 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.
Expand Down Expand Up @@ -395,6 +407,19 @@ default boolean hasActualTypeAnnotation(Class<? extends Annotation> 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 <em>must</em> 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -576,7 +575,7 @@ private void createAndRegisterProperty(Property input) {
return;
}

property.getPersistentEntityTypes().forEach(it -> {
property.getPersistentEntityTypeInformation().forEach(it -> {

if (shouldCreatePersistentEntityFor(it)) {
addPersistentEntity(it);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ public TypeInformation<?> getTypeInformation() {
*/
@Override
public Iterable<? extends TypeInformation<?>> getPersistentEntityTypes() {
return getPersistentEntityTypeInformation();
}

/*
* (non-Javadoc)
* @see org.springframework.data.mapping.PersistentProperty#getPersistentEntityTypeInformation()
*/
@Override
public Iterable<? extends TypeInformation<?>> getPersistentEntityTypeInformation() {

if (isMap() || isCollectionLike()) {
return entityTypeInformation.get();
Expand Down Expand Up @@ -279,11 +288,21 @@ public Association<P> 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()
Expand Down Expand Up @@ -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();
}

/*
Expand All @@ -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)
Expand Down Expand Up @@ -415,9 +436,8 @@ public String toString() {

private Set<TypeInformation<?>> detectEntityTypes(SimpleTypeHolder simpleTypes) {

TypeInformation<?> typeToStartWith = ASSOCIATION_TYPE != null && ASSOCIATION_TYPE.isAssignableFrom(rawType)
? information.getComponentType()
: information;
TypeInformation<?> typeToStartWith = getAssociationTargetTypeInformation();
typeToStartWith = typeToStartWith == null ? information : typeToStartWith;

Set<TypeInformation<?>> result = detectEntityTypes(typeToStartWith);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -74,7 +76,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
&& (isAnnotationPresent(Reference.class) || super.isAssociation()));
private final Lazy<Boolean> isId = Lazy.of(() -> isAnnotationPresent(Id.class));
private final Lazy<Boolean> isVersion = Lazy.of(() -> isAnnotationPresent(Version.class));
private final Lazy<Class<?>> associationTargetType = Lazy.of(() -> {
private final Lazy<TypeInformation<?>> associationTargetType = Lazy.of(() -> {

if (!isAssociation()) {
return null;
Expand All @@ -83,8 +85,8 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
return Optional.of(Reference.class) //
.map(this::findAnnotation) //
.map(Reference::to) //
.map(it -> !Class.class.equals(it) ? it : getActualType()) //
.orElseGet(() -> super.getAssociationTargetType());
.map(it -> !Class.class.equals(it) ? ClassTypeInformation.from(it) : getActualTypeInformation()) //
.orElseGet(() -> super.getAssociationTargetTypeInformation());
});

/**
Expand Down Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected T createPersistentProperty(Property property, BasicPersistentEntity<Ob

when(prop.getTypeInformation()).thenReturn(owner.getTypeInformation());
when(prop.getName()).thenReturn(property.getName());
when(prop.getPersistentEntityTypes()).thenReturn(Collections.EMPTY_SET);
when(prop.getPersistentEntityTypeInformation()).thenReturn(Collections.EMPTY_SET);

try {
Thread.sleep(200);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void discoversComponentTypeCorrectly() {

@Test // DATACMNS-101
void returnsNestedEntityTypeCorrectly() {
assertThat(getProperty(TestClassComplex.class, "testClassSet").getPersistentEntityTypes()).isEmpty();
assertThat(getProperty(TestClassComplex.class, "testClassSet").getPersistentEntityTypeInformation()).isEmpty();
}

@Test // DATACMNS-132
Expand Down Expand Up @@ -198,7 +198,7 @@ void considersCollectionPropertySimpleIfComponentTypeIsSimple() {
void doesNotConsiderPropertyWithTreeMapMapValueAnEntity() {

SamplePersistentProperty property = getProperty(TreeMapWrapper.class, "map");
assertThat(property.getPersistentEntityTypes()).isEmpty();
assertThat(property.getPersistentEntityTypeInformation()).isEmpty();
assertThat(property.isEntity()).isFalse();
}

Expand Down Expand Up @@ -233,7 +233,7 @@ void detectsJMoleculesAssociation() {

assertThat(property.isAssociation()).isTrue();
assertThat(property.getAssociationTargetType()).isEqualTo(JMoleculesAggregate.class);
assertThat(property.getPersistentEntityTypes())
assertThat(property.getPersistentEntityTypeInformation())
.extracting(it -> it.getType())
.containsExactly((Class) JMoleculesAggregate.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<Class<? extends Annotation>, Annotation> getAnnotationCache(SamplePersistentProperty property) {
return (Map<Class<? extends Annotation>, Annotation>) ReflectionTestUtils.getField(property, "annotationCache");
Expand Down