3

I have this exception "ENTITY_INSTANCE_WITH_NULL_ID" when I store data in Postgres (using JPA Lazy Load) and I store javers in MongoDB

Spring Boot: 1.4.0.RELEASE

Sprig Data JPA: 1.4.0.RELEASE

Javers: 2.3.0

I debugged and saw that ID is null if object is a lazy object: org.javers.core.metamodel.type.EntityType:88 "Object cdoId = getIdProperty().get(instance);"

Luu Anh Tuan
  • 33
  • 1
  • 4

2 Answers2

8

When you commit an object to JaVers, its previous version is loaded from JaversRepository and compared with the current version (that version you have just passed to commit() method). In this case JaVers finds the previous version using GlobalId query so TypeName + entity ID. That's why ID can't be null for Entities.

There are two possibilities:

  1. If null ID is normal in this class (according to your domain model) you should map it as ValueObject in JaVers.
  2. If you are using Hibernate, there is common problem with lazy loading proxies. For certain queries, Hibernate doesn't return your real domain objects but dynamic proxy objects which are essentially empty (hence null ID). This technique maybe looks smart but makes your objects garbage until they are initialized by Hibernate. JaVers provides HibernateUnproxyObjectAccessHook which does the cleaning: initializing and un-proxying of your domain objects.

    JaversBuilder.javers().withObjectAccessHook( new HibernateUnproxyObjectAccessHook()).build()

This hook is enabled by default in javers-spring-boot-starter-sql but not in javers-spring-boot-starter-mongo. If you are using Mongo starter, create a JaVers bean on your own, with the hook enabled, see JaversMongoAutoConfiguration.

Bartek Walacik
  • 3,386
  • 1
  • 9
  • 14
  • @BartekWalacik oh, just realized that you're the creator of Javers :-) Great Job!!! very helpful. Thanks – adhg Nov 29 '17 at 18:51
  • I have my tables with inheritance in Spring boot; just to reuse primary key Id which is a Long type. When I try to test my objects to compare, it says the ID is null even though I set them myself. What could be the issue? Note: Thank you for the beautiful library! – Eenvincible Apr 07 '20 at 11:39
  • "If you are using Hibernate". Does this mean that such an _unproxy_ mechanism is not typically required when using EclipseLink? – Nico Van Belle Jun 17 '20 at 06:52
0

I solved the problem by making my own access hook and added to the to the Javers with

.withObjectAccessHook(new EntityAccessHook()).build()

public class EntityAccessHook<T> extends HibernateUnproxyObjectAccessHook<T> {

  @Override
  public Optional<ObjectAccessProxy<T>> createAccessor(T entity) {
    Optional<ObjectAccessProxy<T>> accessProxy = super.createAccessor(entity);
    if (accessProxy.isEmpty() && entity instanceof AbstractUuidEntity) {
      return fromEntityInitializer((AbstractUuidEntity) entity);
    }
    return accessProxy;
  }

  private Optional<ObjectAccessProxy<T>> fromEntityInitializer(
      AbstractUuidEntity abstractUuidEntity) {
    return Optional.of(
        new ObjectAccessProxy(
            () -> abstractUuidEntity,
            abstractUuidEntity.getClass(),
            abstractUuidEntity.getId() == null ? UUID.randomUUID() : abstractUuidEntity.getId()));
  }
}
Dasma
  • 1,023
  • 13
  • 34