diff --git a/pom.xml b/pom.xml
index 2ca5f056c7..9ab21ce869 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-commons
- 3.2.4-SNAPSHOT
+ 3.2.4-GH-3056-SNAPSHOT
Spring Data Core
Core Spring concepts underpinning every Spring Data module.
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 4c2ecc88f2..1fbc89791b 100644
--- a/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java
+++ b/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java
@@ -59,6 +59,7 @@
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
+import org.springframework.data.util.CustomCollections;
import org.springframework.data.util.KotlinReflectionUtils;
import org.springframework.data.util.NullableWrapperConverters;
import org.springframework.data.util.Optionals;
@@ -143,7 +144,6 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
*
* @param initialEntitySet
* @see #setManagedTypes(ManagedTypes)
- *
*/
public void setInitialEntitySet(Set extends Class>> initialEntitySet) {
setManagedTypes(ManagedTypes.fromIterable(initialEntitySet));
@@ -415,16 +415,18 @@ private E doAddPersistentEntity(TypeInformation> typeInformation) {
persistentEntities.put(typeInformation, Optional.of(entity));
}
- PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);
- Map descriptors = new HashMap<>();
+ if (shouldCreateProperties(userTypeInformation)) {
+ PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(type);
+ Map descriptors = new HashMap<>();
- for (PropertyDescriptor descriptor : pds) {
- descriptors.put(descriptor.getName(), descriptor);
- }
+ for (PropertyDescriptor descriptor : pds) {
+ descriptors.put(descriptor.getName(), descriptor);
+ }
- PersistentPropertyCreator persistentPropertyCreator = new PersistentPropertyCreator(entity, descriptors);
- ReflectionUtils.doWithFields(type, persistentPropertyCreator, PersistentPropertyFilter.INSTANCE);
- persistentPropertyCreator.addPropertiesForRemainingDescriptors();
+ PersistentPropertyCreator persistentPropertyCreator = new PersistentPropertyCreator(entity, descriptors);
+ ReflectionUtils.doWithFields(type, persistentPropertyCreator, PersistentPropertyFilter.INSTANCE);
+ persistentPropertyCreator.addPropertiesForRemainingDescriptors();
+ }
entity.verify();
@@ -475,6 +477,35 @@ public Collection> getManagedTypes() {
*/
protected abstract P createPersistentProperty(Property property, E owner, SimpleTypeHolder simpleTypeHolder);
+ /**
+ * Whether to create the {@link PersistentProperty}s for the given {@link TypeInformation}.
+ *
+ * @param typeInformation must not be {@literal null}.
+ * @return {@literal true} properties should be created, {@literal false} otherwise
+ */
+ protected boolean shouldCreateProperties(TypeInformation> typeInformation) {
+
+ Class> type = typeInformation.getType();
+
+ return !typeInformation.isMap() && !isCollectionLike(type);
+ }
+
+ /**
+ * In contrast to TypeInformation, we do not consider types implementing Streamable collection-like as domain types
+ * can implement that type.
+ *
+ * @param type must not be {@literal null}.
+ * @return
+ * @see TypeInformation#isCollectionLike()
+ */
+ private static boolean isCollectionLike(Class> type) {
+
+ return type.isArray() //
+ || Iterable.class.equals(type) //
+ || Streamable.class.equals(type) //
+ || Collection.class.isAssignableFrom(type) || CustomCollections.isCollection(type);
+ }
+
@Override
public void afterPropertiesSet() {
initialize();
@@ -532,6 +563,7 @@ private PersistentPropertyCreator(E entity, Map desc
this.remainingDescriptors = remainingDescriptors;
}
+ @Override
public void doWith(Field field) {
String fieldName = field.getName();
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 7ccdff4a5c..c8af5bd5a3 100644
--- a/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
+++ b/src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java
@@ -157,15 +157,6 @@ public TypeInformation> getTypeInformation() {
@Override
public Iterable extends TypeInformation>> getPersistentEntityTypeInformation() {
-
- if (isMap() || isCollectionLike()) {
- return entityTypeInformation.get();
- }
-
- if (!isEntity()) {
- return Collections.emptySet();
- }
-
return entityTypeInformation.get();
}
@@ -292,6 +283,7 @@ public Class> getActualType() {
return getActualTypeInformation().getType();
}
+ @Override
public boolean usePropertyAccess() {
return usePropertyAccess.get();
}
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 e864b5a2f9..9395ef92cc 100755
--- a/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java
+++ b/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java
@@ -22,14 +22,7 @@
import groovy.lang.MetaClass;
import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
+import java.util.*;
import java.util.function.Supplier;
import org.junit.jupiter.api.BeforeEach;
@@ -49,6 +42,7 @@
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.StreamUtils;
+import org.springframework.data.util.Streamable;
import org.springframework.data.util.TypeInformation;
/**
@@ -285,6 +279,20 @@ void shouldNotCreatePersistentEntityForListButItsGenericTypeArgument() {
.doesNotContain(List.class, ArrayList.class);
}
+ @Test // GH-2390
+ void doesNotCreatePropertiesForMapAndCollectionTypes() {
+
+ assertThat(context.getPersistentEntity(HashSet.class)).isEmpty();
+ assertThat(context.getPersistentEntity(HashMap.class)).isEmpty();
+ }
+
+ @Test // GH-2390
+ void createsPropertiesForStreamableAndIterableTypes() {
+
+ assertThat(context.getPersistentEntity(MyStreamable.class)).hasSize(1);
+ assertThat(context.getPersistentEntity(MyIterable.class)).hasSize(1);
+ }
+
@Test // GH-2390
void detectsEntityTypeEvenIfSimpleTypeHolderConsidersCollectionsSimple() {
@@ -534,4 +542,28 @@ static abstract class Base$$SpringProxy$873fa2e extends Base implements SpringPr
}
+ static class MyIterable implements Iterable {
+
+ String name;
+
+ @Override
+ public Iterator iterator() {
+ return Collections.emptyIterator();
+ }
+ }
+
+ static class MyStreamable implements Streamable {
+
+ String name;
+
+ @Override
+ public Iterator iterator() {
+ return Collections.emptyIterator();
+ }
+ }
+
+ record StreamComponent(String name) {
+
+ }
+
}