Skip to content

Commit 220843f

Browse files
committed
GH-2225 - Improve label determination for inherited entities.
With multiple concrete implementations of an abstract class the determination of the concrete node description for a result `n, collect(r), collect(rn)` was flaky. The abstract class' repository only gives its abstract label as an anchor for the determination. The initial mapping step looks through the whole result to figure the labels for the "root node" but misses out to check for one node that reflects the concrete initial "root node". This leads to the situation that the concrete node description is getting randomly choosen from the random set of possible candidates. Closes #2225
1 parent de0d857 commit 220843f

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

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

+14
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ private List<String> getLabels(MapAccessor queryResult, @Nullable NodeDescriptio
327327
} else if (queryResult instanceof Node) {
328328
Node nodeRepresentation = (Node) queryResult;
329329
nodeRepresentation.labels().forEach(labels::add);
330+
} else if (containsOnePlainNode(queryResult)) {
331+
for (Value value : queryResult.values()) {
332+
if (value.hasType(nodeType)) {
333+
Node node = value.asNode();
334+
for (String label : node.labels()) {
335+
labels.add(label);
336+
}
337+
}
338+
}
330339
} else if (!queryResult.get(Constants.NAME_OF_SYNTHESIZED_ROOT_NODE).isNull()) {
331340
queryResult.get(Constants.NAME_OF_SYNTHESIZED_ROOT_NODE).asNode().labels().forEach(labels::add);
332341
} else if (nodeDescription != null) {
@@ -335,6 +344,11 @@ private List<String> getLabels(MapAccessor queryResult, @Nullable NodeDescriptio
335344
return labels;
336345
}
337346

347+
private boolean containsOnePlainNode(MapAccessor queryResult) {
348+
return StreamSupport.stream(queryResult.values().spliterator(), false)
349+
.filter(value -> value.hasType(nodeType)).count() == 1L;
350+
}
351+
338352
private <ET> ET instantiate(Neo4jPersistentEntity<ET> nodeDescription, MapAccessor values, MapAccessor allValues,
339353
Collection<RelationshipDescription> relationships, Collection<String> surplusLabels,
340354
Object lastMappedEntity) {

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

+22
Original file line numberDiff line numberDiff line change
@@ -3608,6 +3608,28 @@ void findByIdWithTwoLevelInheritance(@Autowired SuperBaseClassRepository superBa
36083608
});
36093609
}
36103610

3611+
@Test // GH-2225
3612+
void findWithTemplateWithTwoLevelInheritance(@Autowired Neo4jTemplate neo4jTemplate) {
3613+
String someValue = "test";
3614+
String concreteClassName = "cc1";
3615+
Inheritance.ConcreteClassA ccA = new Inheritance.ConcreteClassA(concreteClassName, someValue);
3616+
ccA.others = Collections.singletonList(new Inheritance.ConcreteClassB("ccB", 41));
3617+
neo4jTemplate.save(ccA);
3618+
List<Inheritance.SuperBaseClass> ccAs = neo4jTemplate.findAll("MATCH (a:SuperBaseClass{name: 'cc1'})-[r]->(m) " +
3619+
"RETURN a, collect(r), collect(m)",
3620+
Inheritance.SuperBaseClass.class);
3621+
assertThat(ccAs).hasSize(1);
3622+
Inheritance.SuperBaseClass loadedCcA = ccAs.get(0);
3623+
assertThat(loadedCcA).isInstanceOfSatisfying(Inheritance.ConcreteClassA.class, o -> {
3624+
assertThat(o.getName()).isEqualTo(concreteClassName);
3625+
assertThat(o.getConcreteSomething()).isEqualTo(someValue);
3626+
assertThat(o.others).hasSize(1);
3627+
Inheritance.BaseClass relatedNode = o.others.get(0);
3628+
assertThat(relatedNode.getName()).isEqualTo("ccB");
3629+
assertThat(relatedNode).isInstanceOf(Inheritance.ConcreteClassB.class);
3630+
});
3631+
}
3632+
36113633
@Test
36123634
void findAllWithTwoLevelInheritance(@Autowired SuperBaseClassRepository superBaseClassRepository) {
36133635
Inheritance.ConcreteClassA ccA = new Inheritance.ConcreteClassA("cc1", "test");

src/test/java/org/springframework/data/neo4j/integration/shared/common/Inheritance.java

+3
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ public static class ConcreteClassA extends BaseClass {
360360

361361
private final String concreteSomething;
362362

363+
@Relationship("CONNECTED")
364+
public List<BaseClass> others;
365+
363366
public ConcreteClassA(String name, String concreteSomething) {
364367
super(name);
365368
this.concreteSomething = concreteSomething;

0 commit comments

Comments
 (0)