Skip to content

Commit 08ac9d0

Browse files
committed
GH-2420 - Simplify nested projection code.
1 parent 5bc6f49 commit 08ac9d0

File tree

1 file changed

+18
-97
lines changed

1 file changed

+18
-97
lines changed

src/main/java/org/springframework/data/mapping/context/PropertyFilterSupport.java

+18-97
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,14 @@
1515
*/
1616
package org.springframework.data.mapping.context;
1717

18-
import org.springframework.data.mapping.PersistentEntity;
19-
import org.springframework.data.mapping.PersistentProperty;
2018
import org.springframework.data.mapping.PropertyPath;
2119
import org.springframework.data.projection.ProjectionFactory;
2220
import org.springframework.data.projection.ProjectionInformation;
23-
import org.springframework.data.util.TypeInformation;
2421

2522
import java.beans.PropertyDescriptor;
26-
import java.util.ArrayList;
27-
import java.util.Collection;
2823
import java.util.Collections;
29-
import java.util.HashSet;
30-
import java.util.List;
24+
import java.util.Map;
25+
import java.util.concurrent.ConcurrentHashMap;
3126
import java.util.function.Predicate;
3227

3328
/**
@@ -36,10 +31,10 @@
3631
*/
3732
public class PropertyFilterSupport {
3833

39-
public static List<PropertyPath> addPropertiesFrom(Class<?> returnType, Class<?> domainType,
40-
ProjectionFactory projectionFactory,
41-
Predicate<Class<?>> simpleTypePredicate, // TODO SimpleTypeHolder or CustomConversions
42-
MappingContext<?, ?> mappingContext) {
34+
public static Map<PropertyPath, Boolean> addPropertiesFrom(Class<?> returnType, Class<?> domainType,
35+
ProjectionFactory projectionFactory,
36+
Predicate<Class<?>> simpleTypePredicate, // TODO SimpleTypeHolder or CustomConversions
37+
MappingContext<?, ?> mappingContext) {
4338

4439
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(returnType);
4540

@@ -49,11 +44,11 @@ public static List<PropertyPath> addPropertiesFrom(Class<?> returnType, Class<?>
4944

5045
if (openProjection || typeFromHierarchy) {
5146
// *Mark wants to do something with object checks here
52-
return Collections.emptyList();
47+
return Collections.emptyMap();
5348
}
5449
// if ^^ false -> DTO / interface projection
5550

56-
List<PropertyPath> propertyPaths = new ArrayList<>();
51+
Map<PropertyPath, Boolean> propertyPaths = new ConcurrentHashMap<>();
5752
for (PropertyDescriptor inputProperty : projectionInformation.getInputProperties()) {
5853
addPropertiesFrom(returnType, domainType, projectionFactory, simpleTypePredicate, propertyPaths, inputProperty.getName(), mappingContext);
5954
}
@@ -62,7 +57,7 @@ public static List<PropertyPath> addPropertiesFrom(Class<?> returnType, Class<?>
6257

6358
private static void addPropertiesFrom(Class<?> returnedType, Class<?> domainType, ProjectionFactory factory,
6459
Predicate<Class<?>> simpleTypePredicate,
65-
Collection<PropertyPath> filteredProperties, String inputProperty,
60+
Map<PropertyPath, Boolean> filteredProperties, String inputProperty,
6661
MappingContext<?, ?> mappingContext) {
6762

6863
ProjectionInformation projectionInformation = factory.getProjectionInformation(returnedType);
@@ -82,104 +77,30 @@ private static void addPropertiesFrom(Class<?> returnedType, Class<?> domainType
8277
// 2. Something that looks like an entity needs to get processed as such
8378
// 3. Embedded projection
8479
if (simpleTypePredicate.test(propertyType)) {
85-
filteredProperties.add(propertyPath);
80+
filteredProperties.put(propertyPath, false);
8681
} else if (mappingContext.hasPersistentEntityFor(propertyType)) {
87-
// avoid recursion / cycles
88-
if (propertyType.equals(domainType)) {
89-
return;
90-
}
91-
processEntity(propertyPath, filteredProperties, simpleTypePredicate, mappingContext);
92-
82+
filteredProperties.put(propertyPath, true);
9383
} else {
9484
ProjectionInformation nestedProjectionInformation = factory.getProjectionInformation(propertyType);
95-
filteredProperties.add(propertyPath);
9685
// Closed projection should get handled as above (recursion)
9786
if (nestedProjectionInformation.isClosed()) {
87+
filteredProperties.put(propertyPath, false);
9888
for (PropertyDescriptor nestedInputProperty : nestedProjectionInformation.getInputProperties()) {
9989
PropertyPath nestedPropertyPath = propertyPath.nested(nestedInputProperty.getName());
100-
filteredProperties.add(nestedPropertyPath);
90+
91+
if (propertyPath.hasNext() && (domainType.equals(propertyPath.getLeafProperty().getOwningType().getType())
92+
|| returnedType.equals(propertyPath.getLeafProperty().getOwningType().getType()))) {
93+
break;
94+
}
10195
addPropertiesFrom(domainType, returnedType, factory, simpleTypePredicate, filteredProperties,
10296
nestedPropertyPath.toDotPath(), mappingContext);
10397
}
10498
} else {
10599
// an open projection at this place needs to get replaced with the matching (real) entity
106100
PropertyPath domainTypeBasedPropertyPath = PropertyPath.from(propertyPath.toDotPath(), domainType);
107-
processEntity(domainTypeBasedPropertyPath, filteredProperties, simpleTypePredicate, mappingContext);
101+
filteredProperties.put(domainTypeBasedPropertyPath, true);
108102
}
109103
}
110104
}
111105

112-
private static void processEntity(PropertyPath propertyPath, Collection<PropertyPath> filteredProperties,
113-
Predicate<Class<?>> simpleTypePredicate,
114-
MappingContext<?, ?> mappingContext) {
115-
116-
PropertyPath leafProperty = propertyPath.getLeafProperty();
117-
TypeInformation<?> propertyParentType = leafProperty.getOwningType();
118-
String inputProperty = leafProperty.getSegment();
119-
120-
PersistentEntity<?, ?> persistentEntity = mappingContext.getPersistentEntity(propertyParentType);
121-
PersistentProperty<?> persistentProperty = persistentEntity.getPersistentProperty(inputProperty);
122-
Class<?> propertyEntityType = persistentProperty.getActualType();
123-
124-
// Use domain type as root type for the property path
125-
addPropertiesFromEntity(filteredProperties, propertyPath, simpleTypePredicate, propertyEntityType, mappingContext, new HashSet<>());
126-
}
127-
128-
private static void addPropertiesFromEntity(Collection<PropertyPath> filteredProperties, PropertyPath propertyPath,
129-
Predicate<Class<?>> simpleTypePredicate,
130-
Class<?> propertyType, MappingContext<?, ?> mappingContext,
131-
Collection<PersistentEntity<?, ?>> processedEntities) {
132-
133-
PersistentEntity<?, ?> persistentEntityFromProperty = mappingContext.getPersistentEntity(propertyType);
134-
// break the recursion / cycles
135-
if (hasProcessedEntity(persistentEntityFromProperty, processedEntities)) {
136-
return;
137-
}
138-
processedEntities.add(persistentEntityFromProperty);
139-
140-
// save base/root entity/projection type to avoid recursion later
141-
Class<?> pathRootType = propertyPath.getOwningType().getType();
142-
if (mappingContext.hasPersistentEntityFor(pathRootType)) {
143-
processedEntities.add(mappingContext.getPersistentEntity(pathRootType));
144-
}
145-
146-
takeAllPropertiesFromEntity(filteredProperties, simpleTypePredicate, propertyPath, mappingContext, persistentEntityFromProperty, processedEntities);
147-
}
148-
149-
private static boolean hasProcessedEntity(PersistentEntity<?, ?> persistentEntityFromProperty,
150-
Collection<PersistentEntity<?, ?>> processedEntities) {
151-
152-
return processedEntities.contains(persistentEntityFromProperty);
153-
}
154-
155-
private static void takeAllPropertiesFromEntity(Collection<PropertyPath> filteredProperties,
156-
Predicate<Class<?>> simpleTypePredicate, PropertyPath propertyPath,
157-
MappingContext<?, ?> mappingContext,
158-
PersistentEntity<?, ?> persistentEntityFromProperty,
159-
Collection<PersistentEntity<?, ?>> processedEntities) {
160-
161-
filteredProperties.add(propertyPath);
162-
163-
persistentEntityFromProperty.doWithAll(persistentProperty -> {
164-
addPropertiesFromEntity(filteredProperties, propertyPath.nested(persistentProperty.getName()), simpleTypePredicate, mappingContext, processedEntities);
165-
});
166-
}
167-
168-
private static void addPropertiesFromEntity(Collection<PropertyPath> filteredProperties, PropertyPath propertyPath,
169-
Predicate<Class<?>> simpleTypePredicate, MappingContext<?, ?> mappingContext,
170-
Collection<PersistentEntity<?, ?>> processedEntities) {
171-
172-
// break the recursion / cycles
173-
if (filteredProperties.contains(propertyPath)) {
174-
return;
175-
}
176-
Class<?> propertyType = propertyPath.getLeafType();
177-
// simple types can get added directly to the list.
178-
if (simpleTypePredicate.test(propertyType)) {
179-
filteredProperties.add(propertyPath);
180-
// Other types are handled also as entities because there cannot be any nested projection within a real entity.
181-
} else if (mappingContext.hasPersistentEntityFor(propertyType)) {
182-
addPropertiesFromEntity(filteredProperties, propertyPath, simpleTypePredicate, propertyType, mappingContext, processedEntities);
183-
}
184-
}
185106
}

0 commit comments

Comments
 (0)