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 5afb34d5e..fb30c1387 100644
--- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
+++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
@@ -18,19 +18,17 @@ package org.springframework.data.mapping.model;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedHashSet;
+import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.function.Supplier;
+import java.util.stream.Collectors;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.Lazy;
-import org.springframework.data.util.NullableWrapperConverters;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
@@ -64,11 +62,10 @@ public abstract class AbstractPersistentProperty
private final Property property;
private final Lazy hashCode;
private final Lazy usePropertyAccess;
- private final Lazy> entityTypeInformation;
+ private final Lazy>> entityTypeInformation;
private final Lazy isAssociation;
private final Lazy> associationTargetType;
- private final Lazy>> entityTypes;
private final Method getter;
private final Method setter;
@@ -100,10 +97,7 @@ public abstract class AbstractPersistentProperty
.map(TypeInformation::getComponentType) //
.orElse(null));
- this.entityTypeInformation = Lazy.of(() -> Optional.ofNullable(getAssociationOrActualType())
- .filter(it -> !simpleTypeHolder.isSimpleType(it.getType())) //
- .filter(it -> !it.isCollectionLike()) //
- .filter(it -> !it.isMap()).orElse(null));
+ this.entityTypeInformation = Lazy.of(() -> detectEntityTypes(simpleTypeHolder));
this.getter = property.getGetter().orElse(null);
this.setter = property.getSetter().orElse(null);
@@ -115,45 +109,6 @@ public abstract class AbstractPersistentProperty
} else {
this.immutable = false;
}
-
- this.entityTypes = Lazy.of(() -> collectEntityTypes(simpleTypeHolder, information, new LinkedHashSet<>()));
- }
-
- protected Set> collectEntityTypes(SimpleTypeHolder simpleTypeHolder,
- @Nullable TypeInformation> typeInformation, Set> entityTypes) {
-
- if (typeInformation == null || entityTypes.contains(typeInformation)
- || simpleTypeHolder.isSimpleType(typeInformation.getType())) {
- return entityTypes;
- }
-
- if (typeInformation.isMap()) {
-
- collectEntityTypes(simpleTypeHolder, typeInformation.getComponentType(), entityTypes);
- collectEntityTypes(simpleTypeHolder, typeInformation.getMapValueType(), entityTypes);
- return entityTypes;
- }
-
- if (typeInformation.isCollectionLike()) {
-
- collectEntityTypes(simpleTypeHolder, typeInformation.getComponentType(), entityTypes);
- return entityTypes;
- }
-
- if (NullableWrapperConverters.supports(typeInformation.getType())) {
-
- collectEntityTypes(simpleTypeHolder, typeInformation.getActualType(), entityTypes);
- return entityTypes;
- }
-
- if (ASSOCIATION_TYPE != null && ASSOCIATION_TYPE.isAssignableFrom(typeInformation.getType())) {
-
- entityTypes.add(getAssociationOrActualType());
- return entityTypes;
- }
-
- entityTypes.add(typeInformation);
- return entityTypes;
}
protected abstract Association createAssociation();
@@ -211,14 +166,14 @@ public abstract class AbstractPersistentProperty
public Iterable extends TypeInformation>> getPersistentEntityTypes() {
if (isMap() || isCollectionLike()) {
- return entityTypes.get();
+ return entityTypeInformation.get();
}
if (!isEntity()) {
return Collections.emptySet();
}
- return entityTypes.get();
+ return entityTypeInformation.get();
}
/*
@@ -362,7 +317,7 @@ public abstract class AbstractPersistentProperty
*/
@Override
public boolean isEntity() {
- return !isTransient() && entityTypeInformation.getNullable() != null;
+ return !isTransient() && !entityTypeInformation.get().isEmpty();
}
/*
@@ -401,7 +356,11 @@ public abstract class AbstractPersistentProperty
*/
@Override
public Class> getActualType() {
- return getRequiredAssociationOrActualType().getType();
+
+ TypeInformation> targetType = associationTargetType.getNullable();
+ TypeInformation> result = targetType == null ? information.getRequiredActualType() : targetType;
+
+ return result.getType();
}
/*
@@ -454,23 +413,40 @@ public abstract class AbstractPersistentProperty
return property.toString();
}
- @Nullable
- private TypeInformation> getAssociationOrActualType() {
- return getAssociationTypeOr(() -> information.getActualType());
+ private Set> detectEntityTypes(SimpleTypeHolder simpleTypes) {
+
+ TypeInformation> typeToStartWith = ASSOCIATION_TYPE != null && ASSOCIATION_TYPE.isAssignableFrom(rawType)
+ ? information.getComponentType()
+ : information;
+
+ Set> result = detectEntityTypes(typeToStartWith);
+
+ return result.stream()
+ .filter(it -> !simpleTypes.isSimpleType(it.getType()))
+ .filter(it -> !it.getType().equals(ASSOCIATION_TYPE))
+ .collect(Collectors.toSet());
}
- private TypeInformation> getRequiredAssociationOrActualType() {
- return getAssociationTypeOr(() -> information.getRequiredActualType());
- }
+ private Set> detectEntityTypes(@Nullable TypeInformation> source) {
- private TypeInformation> getAssociationTypeOr(Supplier> fallback) {
-
- TypeInformation> result = associationTargetType.getNullable();
-
- if (result != null) {
- return result;
+ if (source == null) {
+ return Collections.emptySet();
}
- return fallback.get();
+ Set> result = new HashSet<>();
+
+ if (source.isMap()) {
+ result.addAll(detectEntityTypes(source.getComponentType()));
+ }
+
+ TypeInformation> actualType = source.getActualType();
+
+ if (source.equals(actualType)) {
+ result.add(source);
+ } else {
+ result.addAll(detectEntityTypes(actualType));
+ }
+
+ return result;
}
}
diff --git a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java
index 4e4de0a7d..3be499745 100755
--- a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java
+++ b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java
@@ -295,6 +295,24 @@ class AbstractMappingContextUnitTests {
.doesNotContain(List.class, ArrayList.class);
}
+ @Test // GH-2390
+ void detectsEntityTypeEveneIfSimpleTypeHolderConsidersCollectionsSimple() {
+
+ context.setSimpleTypeHolder(new SimpleTypeHolder(Collections.emptySet(), true) {
+
+ @Override
+ public boolean isSimpleType(Class> type) {
+ return type.getName().startsWith("java.util.");
+ }
+ });
+
+ context.getPersistentEntity(WithNestedLists.class);
+
+ assertThat(context.getPersistentEntities()) //
+ .map(it -> (Class) it.getType()) //
+ .contains(Base.class);
+ }
+
@Test // GH-2390
void shouldNotCreatePersistentEntityForMapButItsGenericTypeArguments() {