15
15
*/
16
16
package org .springframework .data .mapping .context ;
17
17
18
- import org .springframework .data .mapping .PersistentEntity ;
19
- import org .springframework .data .mapping .PersistentProperty ;
20
18
import org .springframework .data .mapping .PropertyPath ;
21
19
import org .springframework .data .projection .ProjectionFactory ;
22
20
import org .springframework .data .projection .ProjectionInformation ;
23
- import org .springframework .data .util .TypeInformation ;
24
21
25
22
import java .beans .PropertyDescriptor ;
26
- import java .util .ArrayList ;
27
- import java .util .Collection ;
28
23
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 ;
31
26
import java .util .function .Predicate ;
32
27
33
28
/**
36
31
*/
37
32
public class PropertyFilterSupport {
38
33
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 ) {
43
38
44
39
ProjectionInformation projectionInformation = projectionFactory .getProjectionInformation (returnType );
45
40
@@ -49,11 +44,11 @@ public static List<PropertyPath> addPropertiesFrom(Class<?> returnType, Class<?>
49
44
50
45
if (openProjection || typeFromHierarchy ) {
51
46
// *Mark wants to do something with object checks here
52
- return Collections .emptyList ();
47
+ return Collections .emptyMap ();
53
48
}
54
49
// if ^^ false -> DTO / interface projection
55
50
56
- List <PropertyPath > propertyPaths = new ArrayList <>();
51
+ Map <PropertyPath , Boolean > propertyPaths = new ConcurrentHashMap <>();
57
52
for (PropertyDescriptor inputProperty : projectionInformation .getInputProperties ()) {
58
53
addPropertiesFrom (returnType , domainType , projectionFactory , simpleTypePredicate , propertyPaths , inputProperty .getName (), mappingContext );
59
54
}
@@ -62,7 +57,7 @@ public static List<PropertyPath> addPropertiesFrom(Class<?> returnType, Class<?>
62
57
63
58
private static void addPropertiesFrom (Class <?> returnedType , Class <?> domainType , ProjectionFactory factory ,
64
59
Predicate <Class <?>> simpleTypePredicate ,
65
- Collection <PropertyPath > filteredProperties , String inputProperty ,
60
+ Map <PropertyPath , Boolean > filteredProperties , String inputProperty ,
66
61
MappingContext <?, ?> mappingContext ) {
67
62
68
63
ProjectionInformation projectionInformation = factory .getProjectionInformation (returnedType );
@@ -82,104 +77,30 @@ private static void addPropertiesFrom(Class<?> returnedType, Class<?> domainType
82
77
// 2. Something that looks like an entity needs to get processed as such
83
78
// 3. Embedded projection
84
79
if (simpleTypePredicate .test (propertyType )) {
85
- filteredProperties .add (propertyPath );
80
+ filteredProperties .put (propertyPath , false );
86
81
} 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 );
93
83
} else {
94
84
ProjectionInformation nestedProjectionInformation = factory .getProjectionInformation (propertyType );
95
- filteredProperties .add (propertyPath );
96
85
// Closed projection should get handled as above (recursion)
97
86
if (nestedProjectionInformation .isClosed ()) {
87
+ filteredProperties .put (propertyPath , false );
98
88
for (PropertyDescriptor nestedInputProperty : nestedProjectionInformation .getInputProperties ()) {
99
89
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
+ }
101
95
addPropertiesFrom (domainType , returnedType , factory , simpleTypePredicate , filteredProperties ,
102
96
nestedPropertyPath .toDotPath (), mappingContext );
103
97
}
104
98
} else {
105
99
// an open projection at this place needs to get replaced with the matching (real) entity
106
100
PropertyPath domainTypeBasedPropertyPath = PropertyPath .from (propertyPath .toDotPath (), domainType );
107
- processEntity (domainTypeBasedPropertyPath , filteredProperties , simpleTypePredicate , mappingContext );
101
+ filteredProperties . put (domainTypeBasedPropertyPath , true );
108
102
}
109
103
}
110
104
}
111
105
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
- }
185
106
}
0 commit comments