GH-2514 - Avoid non-immutable property mapping recursion.

Closes #2514
This commit is contained in:
Gerrit Meier
2022-03-31 10:17:12 +02:00
parent 52e9a5e591
commit e045ddf071
2 changed files with 31 additions and 1 deletions

View File

@@ -587,7 +587,14 @@ final class DefaultNeo4jEntityConverter implements Neo4jEntityConverter {
for (Relationship possibleRelationship : allMatchingTypeRelationshipsInResult) {
if (targetIdSelector.apply(possibleRelationship) == targetNodeId) {
Object mappedObject = map(possibleValueNode, concreteTargetNodeDescription, null, relationshipsFromResult, nodesFromResult);
// If the target is the same(equal) node, get the related object from the cache.
// Avoiding the call to the map method also breaks an endless cycle of trying to finish
// the property population of _this_ object.
// The initial population will happen at the end of this mapping. This is sufficient because
// it only affects properties not changing the instance of the object.
Object mappedObject = sourceNodeId != null && sourceNodeId.equals(targetNodeId)
? knownObjects.getObject(sourceNodeId)
: map(possibleValueNode, concreteTargetNodeDescription, null, relationshipsFromResult, nodesFromResult);
if (relationshipDescription.hasRelationshipProperties()) {
Object relationshipProperties = map(possibleRelationship,

View File

@@ -824,6 +824,24 @@ class RepositoryIT {
assertThat(slice.getTotalElements()).isEqualTo(2);
assertThat(slice.getTotalPages()).isEqualTo(2);
}
@Test
void findEntityPointingToEqualEntity(@Autowired PetRepository repository) {
doWithSession(session ->
session
.run("CREATE (:Pet{name: 'Pet2'})-[:Has]->(p1:Pet{name: 'Pet1'})-[:Has]->(p1) RETURN p1")
.consume());
List<Pet> allPets = repository.findAllFriends();
for (Pet pet : allPets) {
// everybody has a friend
assertThat(pet.getFriends()).hasSize(1);
// but only Pet1 is its own best friend
if (pet.getName().equals("Pet1")) {
assertThat(pet.getFriends().get(0)).isEqualTo(pet);
}
}
}
}
@Nested
@@ -4149,6 +4167,11 @@ class RepositoryIT {
@Query("MATCH (n:Pet) where n.name='Luna' OPTIONAL MATCH (n)-[r:Has]->(m:Pet) return n, collect(r), collect(m)")
List<Pet> findLunas();
@Query("MATCH (p:Pet)"
+ " OPTIONAL MATCH (p)-[rel:Has]->(op)"
+ " RETURN p, collect(rel), collect(op)")
List<Pet> findAllFriends();
}
interface ImmutablePetRepository extends Neo4jRepository<ImmutablePet, Long> {