-
Notifications
You must be signed in to change notification settings - Fork 619
Description
When using the @DynamicLabels
annotation, objects are getting instantiated as the incorrect type if there are values added to the dynamic labels set. This issue has been tested and confirmed on as late as SDN version 7.5.2. This issue also seems similar to this ticket from last year:
#2886.
Here is an example that demonstrates the issue:
Entities
@Getter
@Setter
@NoArgsConstructor
@Node(primaryLabel = "Vehicle")
public class Vehicle {
@Id
public String id;
@Property(name = "name")
public String name;
@JsonIgnore
@DynamicLabels
public Set<String> labels = Set.of();
}
@Getter
@Setter
@NoArgsConstructor
@Node(primaryLabel = "Car")
public class Car extends Vehicle {
}
@Getter
@Setter
@NoArgsConstructor
@Node(primaryLabel = "Sedan")
public class Sedan extends Car {
}
Repository
@Repository
public interface VehicleRepository extends Neo4jRepository<Vehicle, String> {
@Query("MATCH (vehicle:Vehicle) RETURN vehicle")
List<Vehicle> findAllVehicles();
}
Test
@DataNeo4jTest
class VehicleRepositoryTest (
@Autowired val vehicleRepository: VehicleRepository,
) {
@Test
fun `dynamic labels cause incorrect sub-types`() {
val vehicleWithDynamicLabel = Vehicle().apply {
name = "Vehicle with dynamic label"
labels = setOf("Random Label")
}
val vehicleWithTwoDynamicLabels = Vehicle().apply {
name = "Vehicle with dynamic label"
labels = setOf("Random Label", "Random Label 2")
}
val vehicleWithoutDynamicLabel = Vehicle().apply {
name = "Vehicle without dynamic label"
}
vehicleRepository.saveAll(listOf(vehicleWithDynamicLabel, vehicleWithoutDynamicLabel, vehicleWithTwoDynamicLabels))
val vehicles = vehicleRepository.findAllVehicles();
assertThat(vehicles.filterIsInstance<Sedan>()).isEmpty()
assertThat(vehicles.filterIsInstance<Car>()).isEmpty()
}
}
The above test fails, because vehicleWithDynamicLabel
and vehicleWithTwoDynamicLabels
get mapped to Car
objects when retrieved from the database, when they are nodes of the parent type Vehicle
. vehicleWithoutDynamicLabel
is correctly mapped to a Vehicle
object because it does not have dynamic labels. With one or two dynamic labels, both Vehicle
nodes still mapped to Car
objects, neither were instantiated as the grandchild type Sedan
.
We can see in the following picture, that two of the three Vehicle
nodes get mapped to Car
because they have dynamic labels:
Image