Skip to content

@DynamicLabel with non-abstract class inheritance #2886

@LGDOI

Description

@LGDOI

SDN 6.3.18 returns incorrect instance type when a dynamic label is set on a node.

I have an example repo but here is a summary of the problem.

Entities

Given the following entity types

@Getter @Setter @NoArgsConstructor @Node(primaryLabel = "Fruit") public abstract class Fruit { @Id protected String id; @JsonIgnore @DynamicLabels protected Set<String> labels = Set.of(); } 

Subclass of Fruit

 @Getter @Setter @NoArgsConstructor @Node(primaryLabel = "MagicalFruit") public class MagicalFruit extends Fruit { @Serial private static final long serialVersionUID = -8776591636750117301L; @Property(name = "volume") private double volume; @Property(name = "color") private String color; @Override public int hashCode() { return new HashCodeBuilder().append(id).hashCode(); } @Override public boolean equals(Object obj) { return obj == this || (obj instanceof MagicalFruit other && Objects.equals(id, other.id)); } } 

Sub classes of MagicalFruit

@Getter @Setter @NoArgsConstructor @Node(primaryLabel = "Apple") public class Apple extends MagicalFruit { @Override public boolean equals(Object obj) { return obj == this || (obj instanceof Apple other && Objects.equals(id, other.id)); } } 

and

@Getter @Setter @NoArgsConstructor @Node(primaryLabel = "Orange") public class Orange extends MagicalFruit { @Override public boolean equals(Object obj) { return obj == this || (obj instanceof Orange other && Objects.equals(id, other.id)); } } 

Repository

@Repository public interface FruitRepository extends Neo4jRepository<Fruit, String> { @Query("MATCH (f:Fruit) RETURN f") List<Fruit> findAllFruits(); } 

Test

@DataNeo4jTest class FruitRepositoryTest( val fruitRepository: FruitRepository, ) { @Test fun `debug dynamic label and deserialization`() { val applesWithDynamicLabel = List(2) { Apple().apply { volume = it.toDouble() color = "Red" labels = setOf("Apple_$it") } } val applesWithoutDynamicLabel = List(2) { Apple().apply { volume = it.toDouble() color = "Blue" } } val orangesWithDynamicLabel = List(2) { Orange().apply { volume = it.toDouble() color = "Red" labels = setOf("Orange_$it") } } val orangesWithoutDynamicLabel = List(2) { Orange().apply { volume = it.toDouble() color = "Yellow" } } fruitRepository.saveAll( applesWithDynamicLabel + applesWithoutDynamicLabel + orangesWithDynamicLabel + orangesWithoutDynamicLabel) val fruits = fruitRepository.findAllFruits() assertThat(fruits.filterIsInstance<Apple>()).hasSize(4) assertThat(fruits.filterIsInstance<Orange>()).hasSize(4) } } 

The above test fails because fruits contains instances of MagicalFruit when dynamic labels are set.

Other Findings

When I change MagicalFruit class to an abstract class, the same test pass.

#2529 is very similar bug but that example has abstract on Feline class.

Is this required to have only one concrete class as a leaf node of the inheritance hierarchy for dynamic label to work?

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions