Skip to content

Commit b10ea7f

Browse files
committed
GH-2591 - Fix StackOverflow on first level of recursive projections.
Closes #2591
1 parent 1af7355 commit b10ea7f

File tree

5 files changed

+32
-5
lines changed

5 files changed

+32
-5
lines changed

src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.springframework.data.neo4j.core.mapping.DtoInstantiatingConverter;
7373
import org.springframework.data.neo4j.core.mapping.EntityFromDtoInstantiatingConverter;
7474
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
75+
import org.springframework.data.neo4j.core.mapping.IdDescription;
7576
import org.springframework.data.neo4j.core.mapping.MappingSupport;
7677
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
7778
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity;
@@ -978,7 +979,8 @@ private Entity saveRelatedNode(Object entity, NodeDescription<?> targetNodeDescr
978979
@SuppressWarnings("unchecked")
979980
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);
980981
String idPropertyName = targetPersistentEntity.getIdProperty().getPropertyName();
981-
boolean assignedId = targetPersistentEntity.getIdDescription().isAssignedId();
982+
IdDescription idDescription = targetPersistentEntity.getIdDescription();
983+
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
982984
if (!includeProperty.isNotFiltering()) {
983985
properties.entrySet()
984986
.removeIf(e -> {

src/main/java/org/springframework/data/neo4j/core/PropertyFilterSupport.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,10 @@ private static void addPropertiesFrom(Class<?> domainType, Class<?> returnedType
146146
TypeInformation<?> typeInformation = currentTypeInformation.getProperty(nestedInputProperty.getName());
147147
ProjectionPathProcessor nextProjectionPathProcessor = projectionPathProcessor.next(nestedInputProperty, typeInformation);
148148

149-
if (projectionPathProcessor.isChildLevel() && (domainType.equals(nextProjectionPathProcessor.typeInformation.getType())
150-
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getType()))) {
149+
if (projectionPathProcessor.isChildLevel() &&
150+
(domainType.equals(nextProjectionPathProcessor.typeInformation.getType())
151+
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getActualType().getType())
152+
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getType()))) {
151153
break;
152154
}
153155

src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.neo4j.cypherdsl.core.Cypher.asterisk;
2020
import static org.neo4j.cypherdsl.core.Cypher.parameter;
2121

22+
import org.springframework.data.neo4j.core.mapping.IdDescription;
2223
import reactor.core.publisher.Flux;
2324
import reactor.core.publisher.Mono;
2425
import reactor.util.function.Tuple2;
@@ -1068,7 +1069,8 @@ private Mono<Entity> saveRelatedNode(Object relatedNode, Neo4jPersistentEntity<?
10681069
@SuppressWarnings("unchecked")
10691070
Function<Object, Map<String, Object>> binderFunction = neo4jMappingContext.getRequiredBinderFunctionFor(entityType);
10701071
String idPropertyName = targetNodeDescription.getIdProperty().getPropertyName();
1071-
boolean assignedId = targetNodeDescription.getIdDescription().isAssignedId();
1072+
IdDescription idDescription = targetNodeDescription.getIdDescription();
1073+
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
10721074
binderFunction = binderFunction.andThen(tree -> {
10731075
@SuppressWarnings("unchecked")
10741076
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);

src/main/java/org/springframework/data/neo4j/core/TemplateSupport.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.data.mapping.PropertyPath;
4545
import org.springframework.data.neo4j.core.mapping.Constants;
4646
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
47+
import org.springframework.data.neo4j.core.mapping.IdDescription;
4748
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
4849
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity;
4950
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentProperty;
@@ -280,7 +281,8 @@ static <T> FilteredBinderFunction<T> createAndApplyPropertyFilter(
280281
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);
281282

282283
String idPropertyName = entityMetaData.getIdProperty().getPropertyName();
283-
boolean assignedId = entityMetaData.getIdDescription().isAssignedId();
284+
IdDescription idDescription = entityMetaData.getIdDescription();
285+
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
284286
if (!includeProperty.isNotFiltering()) {
285287
properties.entrySet()
286288
.removeIf(e -> {

src/test/java/org/springframework/data/neo4j/integration/movies/imperative/AdvancedMappingIT.java

+19
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ interface MovieWithSequelEntity {
132132
Movie getSequel();
133133
}
134134

135+
interface MovieWithMovieList {
136+
String getTitle();
137+
138+
List<MovieWithMovieList> getSequel();
139+
}
140+
135141
interface MovieRepository extends Neo4jRepository<Movie, String> {
136142

137143
MovieProjection findProjectionByTitle(String title);
@@ -496,6 +502,19 @@ void mapPathWithMultipleSameTypeRelationships(@Autowired MovieRepository reposit
496502
assertThat(movies.get(0).getActors()).hasSize(6);
497503
}
498504

505+
@Test // GH-2591
506+
void createPropertyFilterPathCorrectly(@Autowired Neo4jTemplate neo4jTemplate) {
507+
Movie movie = new Movie("Test", "Movie");
508+
neo4jTemplate.saveAs(movie, MovieWithMovieList.class);
509+
510+
Movie foundMovie = neo4jTemplate.findOne("MATCH (m:Movie{title:'Test'}) return m", Collections.emptyMap(), Movie.class).get();
511+
assertThat(foundMovie.getTitle()).isEqualTo("Test");
512+
assertThat(foundMovie.getDescription()).isNull();
513+
514+
// clean up to keep the other tests healthy
515+
neo4jTemplate.deleteById("Test", Movie.class);
516+
}
517+
499518
@Configuration
500519
@EnableTransactionManagement
501520
@EnableNeo4jRepositories(considerNestedRepositories = true)

0 commit comments

Comments
 (0)