Search code examples
javers

JaversException ENTITY_INSTANCE_WITH_NULL_ID for ignored id


Using javers 5.11.2 I get the following exception although the id is set to be ignored. Why is that?

JaversException ENTITY_INSTANCE_WITH_NULL_ID: Found Entity instance 'my.package.javers.Leaf' with null Id-property 'id'

Update: I learned that

JaVers matches only objects with the same GlobalId

The id is specified using javax.persistence.Id. However, with each ORM it is possible to have an entity with a collection, then add a new element without id to that entity and then save it (CascadeType.Persist).

Is there any way to compare objects with javers in such a case?

Example (used lombok for boiler plate code).

The leaf:

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
public class Leaf {

    @DiffIgnore  <============ id is ignored
    @Id
    private Long id;

    private String color;

}

The tree:

@Builder
@Data
@Entity
public class Tree {

    @Id
    private Long id;

    private String name;

    @OneToMany
    private Set<Leaf> leafs;

}

Test adds a leaf to the oakSecond without an id set. The diff cannot be made. An Exception is thrown.

@Test
public void testCompare_AddLeafToTree() {
    Leaf leaf = Leaf.builder().id(1L).color("11").build();
    Set<Leaf> leafsOfOakFirst = new HashSet<>();
    leafsOfOakFirst.add(leaf);

    Tree oakFirst = Tree.builder().id(1L).name("oakFirst").build();
    oakFirst.setLeafs(leafsOfOakFirst);

    Set<Leaf> leafsOfOakSecond = new HashSet<>();
    leafsOfOakSecond.add(leaf);
    leafsOfOakSecond.add(Leaf.builder().color("12").build());

    Tree oakSecond = Tree.builder().id(1L).name("oakFirst").build();
    oakSecond.setLeafs(leafsOfOakSecond);

    Javers javers = JaversBuilder.javers().build();

    Changes changes = javers.compare(oakFirst, oakSecond).getChanges();

    assertThat(changes).isNotEmpty();
}

Same with the following definition of the Javers instance:

EntityDefinition leafEntityDefinition = EntityDefinitionBuilder.entityDefinition(Leaf.class).withIgnoredProperties("id").build();
Javers javers = JaversBuilder.javers().registerEntity(leafEntityDefinition).build();

Solution

  • You can't pass an Entity to Javers with null Id because it would be non-identifiable. If you use Hibernate to generate your Ids, make sure that you pass your object to javers.commit() after hibernate are done with its job. That's how the @JaversSpringDataAuditable aspect works.

    Alternatively, you can model those objects with unstable IDs as Value Object in Javers.