1

I am using envers to audit my entities. My code looks somewhat like this

@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
@AuditOverride( forClass = Task.class, isAudited = true )
public class Job extends Task
{...}

@Inheritance( strategy = InheritanceType.JOINED )
@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
public class Task
{ 
    ...
    @ManyToOne( fetch = FetchType.LAZY )
    @LazyToOne( value = LazyToOneOption.NO_PROXY )
    @Fetch( value = FetchMode.SELECT )
    @JoinColumn( nam = "id_util" )
    @Audited( targetAuditMode = RelationTargetAuditMode.AUDITED )
    private Utility utility;
}

@Entity
@DynamicInsert
@DynamicUpdate
@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )
public class Utility
{
    @Override
    public String toString()
    {
        StringBuilder builder = new StringBuilder();
        builder.append( this.getClass().getName() ).append( "@" ).append( getId() );
        builder.append( "[" );
        appendAttributeValues( builder );
        builder.append( "]" );
        return builder.toString();
    }

    public Long getId()
    {
        return id;
    }
}

When I try to fetch the revisions of a certain job entity, the field utility is not loaded correctly. Instead, hibernate gives a

Method threw 'org.hibernate.exception.GenericJDBCException' exception. Cannot evaluate Utility$HibernateProxy$9GVDBIUC.toString()

The rest of the entity revisions which consists of strings and numbers is loaded just fine. I also don't get this error when auditing and querying other entities which do not have an inheritance structure.

The _aud tables for the entities Job, Task and Utility are all filled correctly. What might be causing this error?

Balint Gyapjas
  • 314
  • 3
  • 10
  • Can you include the code of the ```Utility``` entity also? Thanks – jccampanero Aug 20 '20 at 12:55
  • The utility contains simple types and references to other entitites different from the ones regarding this problem. I added the annotations I am using. – Balint Gyapjas Aug 20 '20 at 13:32
  • Please, can you at least include the ```toString``` method definition of the entity, if any? – jccampanero Aug 20 '20 at 13:54
  • toString() included – Balint Gyapjas Aug 21 '20 at 17:10
  • Thank you. And what is the definition of the method ```appendAttributeValues```? I am sorry to ask, the problem could be related with some code in the implementation of the method ```toString``. Say, for instance, that you reference a relation that does not exists or something like that. If it is not the case, we can think in others reasons. – jccampanero Aug 21 '20 at 18:08

2 Answers2

1

Before using linked object you should "materialize" proxy-object created by hibernate, like sayed in this answer: https://stackoverflow.com/a/2216603/3744622

Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
    entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
        .getImplementation();
}
return entity;

or, for instance, using special method unproxy:

Object unproxiedObject = Hibernate.unproxy(proxiedObject);
hwak
  • 272
  • 1
  • 3
  • 16
0

TLDR The reason is inconsistent audit data. It happens when you you start auditing already existing entities and their relations.

Solution Copy all entity data in the corresonding aud table with rev = 1,revtype = 0. Insert rev=1, revtstmp=0 into revinfo table.

See also Safe Envers queries when the audit history is incomplete

Explanation Because the entity data existed before envers is integrated, the audit tables are initially empty. When you update an entity A whichs owns a reference to entity B, an audit records is created in A_aud but not in B_aud. When A is queried for revisions it tries to look up the referred entity B in the emtpy B_aud and yields an EntityNotFoundException, which got wrapped up in the given GenericJDBCException.

Balint Gyapjas
  • 314
  • 3
  • 10