Skip to content

Commit d1782c0

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 d2dd287 commit d1782c0

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
@@ -3571,6 +3571,28 @@ void findByIdWithTwoLevelInheritance(@Autowired SuperBaseClassRepository superBa
35713571
});
35723572
}
35733573

3574+
@Test // GH-2225
3575+
void findWithTemplateWithTwoLevelInheritance(@Autowired Neo4jTemplate neo4jTemplate) {
3576+
String someValue = "test";
3577+
String concreteClassName = "cc1";
3578+
Inheritance.ConcreteClassA ccA = new Inheritance.ConcreteClassA(concreteClassName, someValue);
3579+
ccA.others = Collections.singletonList(new Inheritance.ConcreteClassB("ccB", 41));
3580+
neo4jTemplate.save(ccA);
3581+
List<Inheritance.SuperBaseClass> ccAs = neo4jTemplate.findAll("MATCH (a:SuperBaseClass{name: 'cc1'})-[r]->(m) " +
3582+
"RETURN a, collect(r), collect(m)",
3583+
Inheritance.SuperBaseClass.class);
3584+
assertThat(ccAs).hasSize(1);
3585+
Inheritance.SuperBaseClass loadedCcA = ccAs.get(0);
3586+
assertThat(loadedCcA).isInstanceOfSatisfying(Inheritance.ConcreteClassA.class, o -> {
3587+
assertThat(o.getName()).isEqualTo(concreteClassName);
3588+
assertThat(o.getConcreteSomething()).isEqualTo(someValue);
3589+
assertThat(o.others).hasSize(1);
3590+
Inheritance.BaseClass relatedNode = o.others.get(0);
3591+
assertThat(relatedNode.getName()).isEqualTo("ccB");
3592+
assertThat(relatedNode).isInstanceOf(Inheritance.ConcreteClassB.class);
3593+
});
3594+
}
3595+
35743596
@Test
35753597
void findAllWithTwoLevelInheritance(@Autowired SuperBaseClassRepository superBaseClassRepository) {
35763598
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
@@ -361,6 +361,9 @@ public static class ConcreteClassA extends BaseClass {
361361

362362
private final String concreteSomething;
363363

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

0 commit comments

Comments
 (0)