GH-2591 - Fix StackOverflow on first level of recursive projections.
Closes #2591
This commit is contained in:
@@ -72,6 +72,7 @@ import org.springframework.data.neo4j.core.mapping.CypherGenerator;
|
||||
import org.springframework.data.neo4j.core.mapping.DtoInstantiatingConverter;
|
||||
import org.springframework.data.neo4j.core.mapping.EntityFromDtoInstantiatingConverter;
|
||||
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
|
||||
import org.springframework.data.neo4j.core.mapping.IdDescription;
|
||||
import org.springframework.data.neo4j.core.mapping.MappingSupport;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity;
|
||||
@@ -978,7 +979,8 @@ public final class Neo4jTemplate implements
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);
|
||||
String idPropertyName = targetPersistentEntity.getIdProperty().getPropertyName();
|
||||
boolean assignedId = targetPersistentEntity.getIdDescription().isAssignedId();
|
||||
IdDescription idDescription = targetPersistentEntity.getIdDescription();
|
||||
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
|
||||
if (!includeProperty.isNotFiltering()) {
|
||||
properties.entrySet()
|
||||
.removeIf(e -> {
|
||||
|
||||
@@ -146,8 +146,10 @@ public final class PropertyFilterSupport {
|
||||
TypeInformation<?> typeInformation = currentTypeInformation.getProperty(nestedInputProperty.getName());
|
||||
ProjectionPathProcessor nextProjectionPathProcessor = projectionPathProcessor.next(nestedInputProperty, typeInformation);
|
||||
|
||||
if (projectionPathProcessor.isChildLevel() && (domainType.equals(nextProjectionPathProcessor.typeInformation.getType())
|
||||
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getType()))) {
|
||||
if (projectionPathProcessor.isChildLevel() &&
|
||||
(domainType.equals(nextProjectionPathProcessor.typeInformation.getType())
|
||||
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getActualType().getType())
|
||||
|| returnedType.equals(nextProjectionPathProcessor.typeInformation.getType()))) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.neo4j.cypherdsl.core.Cypher.anyNode;
|
||||
import static org.neo4j.cypherdsl.core.Cypher.asterisk;
|
||||
import static org.neo4j.cypherdsl.core.Cypher.parameter;
|
||||
|
||||
import org.springframework.data.neo4j.core.mapping.IdDescription;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
@@ -1068,7 +1069,8 @@ public final class ReactiveNeo4jTemplate implements
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<Object, Map<String, Object>> binderFunction = neo4jMappingContext.getRequiredBinderFunctionFor(entityType);
|
||||
String idPropertyName = targetNodeDescription.getIdProperty().getPropertyName();
|
||||
boolean assignedId = targetNodeDescription.getIdDescription().isAssignedId();
|
||||
IdDescription idDescription = targetNodeDescription.getIdDescription();
|
||||
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
|
||||
binderFunction = binderFunction.andThen(tree -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.neo4j.core.mapping.Constants;
|
||||
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
|
||||
import org.springframework.data.neo4j.core.mapping.IdDescription;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity;
|
||||
import org.springframework.data.neo4j.core.mapping.Neo4jPersistentProperty;
|
||||
@@ -280,7 +281,8 @@ public final class TemplateSupport {
|
||||
Map<String, Object> properties = (Map<String, Object>) tree.get(Constants.NAME_OF_PROPERTIES_PARAM);
|
||||
|
||||
String idPropertyName = entityMetaData.getIdProperty().getPropertyName();
|
||||
boolean assignedId = entityMetaData.getIdDescription().isAssignedId();
|
||||
IdDescription idDescription = entityMetaData.getIdDescription();
|
||||
boolean assignedId = idDescription.isAssignedId() || idDescription.isExternallyGeneratedId();
|
||||
if (!includeProperty.isNotFiltering()) {
|
||||
properties.entrySet()
|
||||
.removeIf(e -> {
|
||||
|
||||
@@ -132,6 +132,12 @@ class AdvancedMappingIT {
|
||||
Movie getSequel();
|
||||
}
|
||||
|
||||
interface MovieWithMovieList {
|
||||
String getTitle();
|
||||
|
||||
List<MovieWithMovieList> getSequel();
|
||||
}
|
||||
|
||||
interface MovieRepository extends Neo4jRepository<Movie, String> {
|
||||
|
||||
MovieProjection findProjectionByTitle(String title);
|
||||
@@ -496,6 +502,19 @@ class AdvancedMappingIT {
|
||||
assertThat(movies.get(0).getActors()).hasSize(6);
|
||||
}
|
||||
|
||||
@Test // GH-2591
|
||||
void createPropertyFilterPathCorrectly(@Autowired Neo4jTemplate neo4jTemplate) {
|
||||
Movie movie = new Movie("Test", "Movie");
|
||||
neo4jTemplate.saveAs(movie, MovieWithMovieList.class);
|
||||
|
||||
Movie foundMovie = neo4jTemplate.findOne("MATCH (m:Movie{title:'Test'}) return m", Collections.emptyMap(), Movie.class).get();
|
||||
assertThat(foundMovie.getTitle()).isEqualTo("Test");
|
||||
assertThat(foundMovie.getDescription()).isNull();
|
||||
|
||||
// clean up to keep the other tests healthy
|
||||
neo4jTemplate.deleteById("Test", Movie.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableNeo4jRepositories(considerNestedRepositories = true)
|
||||
|
||||
Reference in New Issue
Block a user