@@ -47,46 +47,55 @@ public static List<PropertyPath> getInputProperties(ResultProcessor resultProces
47
47
ReturnedType returnedType = resultProcessor .getReturnedType ();
48
48
List <PropertyPath > filteredProperties = new ArrayList <>();
49
49
50
+ boolean isProjecting = returnedType .isProjecting ();
50
51
for (String inputProperty : returnedType .getInputProperties ()) {
51
- if (returnedType . isProjecting () ) {
52
+ if (isProjecting ) {
52
53
addPropertiesFrom (returnedType .getDomainType (), returnedType .getReturnedType (), factory ,
53
54
filteredProperties , inputProperty , mappingContext );
54
55
} else {
55
56
addPropertiesFromEntity (filteredProperties , PropertyPath .from (inputProperty , returnedType .getDomainType ()),
56
57
returnedType .getReturnedType (), mappingContext , new HashSet <>());
57
58
}
58
59
}
59
- return returnedType . isProjecting () ? filteredProperties : Collections .emptyList ();
60
+ return isProjecting ? filteredProperties : Collections .emptyList ();
60
61
}
61
62
62
63
public static List <PropertyPath > addPropertiesFrom (Class <?> returnType , Class <?> domainType ,
63
64
ProjectionFactory projectionFactory ,
64
65
Neo4jMappingContext neo4jMappingContext ) {
65
66
66
67
ProjectionInformation projectionInformation = projectionFactory .getProjectionInformation (returnType );
67
- List <PropertyPath > pps = new ArrayList <>();
68
+ List <PropertyPath > propertyPaths = new ArrayList <>();
68
69
for (PropertyDescriptor inputProperty : projectionInformation .getInputProperties ()) {
69
- addPropertiesFrom (returnType , domainType , projectionFactory , pps , inputProperty .getName (), neo4jMappingContext );
70
+ addPropertiesFrom (returnType , domainType , projectionFactory , propertyPaths , inputProperty .getName (), neo4jMappingContext );
70
71
}
71
- return pps ;
72
+ return propertyPaths ;
72
73
}
73
74
74
75
private static void addPropertiesFrom (Class <?> domainType , Class <?> returnedType , ProjectionFactory factory ,
75
76
Collection <PropertyPath > filteredProperties , String inputProperty ,
76
77
Neo4jMappingContext mappingContext ) {
77
78
78
- ProjectionInformation projectionInformation1 = factory .getProjectionInformation (returnedType );
79
+ ProjectionInformation projectionInformation = factory .getProjectionInformation (returnedType );
79
80
PropertyPath propertyPath ;
80
- if (projectionInformation1 .isClosed ()) {
81
+
82
+ // If this is a closed projection we can assume that the return type (possible projection type) contains
83
+ // only fields accessible with a property path.
84
+ if (projectionInformation .isClosed ()) {
81
85
propertyPath = PropertyPath .from (inputProperty , returnedType );
82
86
} else {
87
+ // otherwise the domain type is used right from the start
83
88
propertyPath = PropertyPath .from (inputProperty , domainType );
84
89
}
85
90
86
91
Class <?> propertyType = propertyPath .getLeafType ();
92
+ // 1. simple types can be added directly
93
+ // 2. something that looks like an entity needs to get processed as such
94
+ // 3. Embedded projection
87
95
if (Neo4jSimpleTypes .HOLDER .isSimpleType (propertyType ) || mappingContext .hasCustomWriteTarget (propertyType )) {
88
96
filteredProperties .add (propertyPath );
89
97
} else if (mappingContext .hasPersistentEntityFor (propertyType )) {
98
+ // avoid recursion / cycles
90
99
if (propertyType .equals (domainType )) {
91
100
return ;
92
101
}
@@ -95,9 +104,10 @@ private static void addPropertiesFrom(Class<?> domainType, Class<?> returnedType
95
104
} else {
96
105
ProjectionInformation nestedProjectionInformation = factory .getProjectionInformation (propertyType );
97
106
filteredProperties .add (propertyPath );
107
+ // Closed projection should get handled as above (recursion)
98
108
if (nestedProjectionInformation .isClosed ()) {
99
- for (PropertyDescriptor secondInputProperty : nestedProjectionInformation .getInputProperties ()) {
100
- PropertyPath nestedPropertyPath = propertyPath .nested (secondInputProperty .getName ());
109
+ for (PropertyDescriptor nestedInputProperty : nestedProjectionInformation .getInputProperties ()) {
110
+ PropertyPath nestedPropertyPath = propertyPath .nested (nestedInputProperty .getName ());
101
111
filteredProperties .add (nestedPropertyPath );
102
112
addPropertiesFrom (domainType , returnedType , factory , filteredProperties ,
103
113
nestedPropertyPath .toDotPath (), mappingContext );
@@ -124,6 +134,7 @@ private static void addPropertiesFromEntity(Collection<PropertyPath> filteredPro
124
134
Collection <Neo4jPersistentEntity <?>> processedEntities ) {
125
135
126
136
Neo4jPersistentEntity <?> persistentEntityFromProperty = mappingContext .getPersistentEntity (propertyType );
137
+ // break the recursion / cycles
127
138
if (hasProcessedEntity (persistentEntityFromProperty , processedEntities )) {
128
139
return ;
129
140
}
@@ -151,6 +162,7 @@ private static void takeAllPropertiesFromEntity(Collection<PropertyPath> filtere
151
162
152
163
filteredProperties .add (propertyPath );
153
164
165
+ // there is no unifying accessor for plain properties and associations, need to do the same thing twice.
154
166
for (String propertyName : propertyNames ) {
155
167
addPropertiesFrom (filteredProperties , propertyPath .nested (propertyName ), mappingContext , processedEntities );
156
168
}
@@ -170,8 +182,10 @@ private static void addPropertiesFrom(Collection<PropertyPath> filteredPropertie
170
182
return ;
171
183
}
172
184
Class <?> propertyType = propertyPath .getLeafType ();
185
+ // simple types can get added directly to the list.
173
186
if (Neo4jSimpleTypes .HOLDER .isSimpleType (propertyType ) || mappingContext .hasCustomWriteTarget (propertyType )) {
174
187
filteredProperties .add (propertyPath );
188
+ // Other types are handled also as entites because there cannot be any nested projection within a real entity.
175
189
} else if (mappingContext .hasPersistentEntityFor (propertyType )) {
176
190
addPropertiesFromEntity (filteredProperties , propertyPath , propertyType , mappingContext , processedEntities );
177
191
}
0 commit comments