Skip to content

Commit ae26328

Browse files
committed
GH-2514 - Avoid non-immutable property mapping recursion.
Closes #2514
1 parent 2e785ba commit ae26328

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jEntityConverter.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,14 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
607607
for (Relationship possibleRelationship : allMatchingTypeRelationshipsInResult) {
608608
if (targetIdSelector.apply(possibleRelationship) == targetNodeId) {
609609

610-
Object mappedObject = map(possibleValueNode, concreteTargetNodeDescription, null, relationshipsFromResult, nodesFromResult);
610+
// If the target is the same(equal) node, get the related object from the cache.
611+
// Avoiding the call to the map method also breaks an endless cycle of trying to finish
612+
// the property population of _this_ object.
613+
// The initial population will happen at the end of this mapping. This is sufficient because
614+
// it only affects properties not changing the instance of the object.
615+
Object mappedObject = sourceNodeId != null && sourceNodeId.equals(targetNodeId)
616+
? knownObjects.getObject(sourceNodeId)
617+
: map(possibleValueNode, concreteTargetNodeDescription, null, relationshipsFromResult, nodesFromResult);
611618
if (relationshipDescription.hasRelationshipProperties()) {
612619

613620
Object relationshipProperties = map(possibleRelationship,

src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java

+23
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,24 @@ void findPageByCustomQueryWithCountShouldWork(@Autowired PersonRepository reposi
830830
assertThat(slice.getTotalElements()).isEqualTo(2);
831831
assertThat(slice.getTotalPages()).isEqualTo(2);
832832
}
833+
834+
@Test
835+
void findEntityPointingToEqualEntity(@Autowired PetRepository repository) {
836+
doWithSession(session ->
837+
session
838+
.run("CREATE (:Pet{name: 'Pet2'})-[:Has]->(p1:Pet{name: 'Pet1'})-[:Has]->(p1) RETURN p1")
839+
.consume());
840+
841+
List<Pet> allPets = repository.findAllFriends();
842+
for (Pet pet : allPets) {
843+
// everybody has a friend
844+
assertThat(pet.getFriends()).hasSize(1);
845+
// but only Pet1 is its own best friend
846+
if (pet.getName().equals("Pet1")) {
847+
assertThat(pet.getFriends().get(0)).isEqualTo(pet);
848+
}
849+
}
850+
}
833851
}
834852

835853
@Nested
@@ -4273,6 +4291,11 @@ interface PetRepository extends Neo4jRepository<Pet, Long> {
42734291

42744292
@Query("MATCH (n:Pet) where n.name='Luna' OPTIONAL MATCH (n)-[r:Has]->(m:Pet) return n, collect(r), collect(m)")
42754293
List<Pet> findLunas();
4294+
4295+
@Query("MATCH (p:Pet)"
4296+
+ " OPTIONAL MATCH (p)-[rel:Has]->(op)"
4297+
+ " RETURN p, collect(rel), collect(op)")
4298+
List<Pet> findAllFriends();
42764299
}
42774300

42784301
interface ImmutablePetRepository extends Neo4jRepository<ImmutablePet, Long> {

0 commit comments

Comments
 (0)