Hibernate Envers and “Javassist Enhancement failed” Exception
-
18-01-2021 - |
Question
We are using Hibernate Envers and have the following situation:
A class BusinessObjectType
and a class Identity
with a reference to BusinessObjectType
:
@Entity
@Table( name = "ID_IDENTITY" )
@Audited
public class Identity {
@ManyToOne
@JoinColumn( name = "BO_TYPE_ID" )
@IndexColumn( name = "INDEX_BO_BO_TYPE" )
private BusinessObjectType businessObjectType;
[…]
}
We then query for all the version of Identity with:
AuditQuery auditQuery = auditReader.createQuery().forRevisionsOfEntity(
Identity.class,
false,
true );
auditQuery.add( AuditEntity.id().eq( dbid ) );
@SuppressWarnings( "unchecked" )
List< Object[]> history = (List< Object[]>) auditQuery.getResultList();
If the stored identity does not have a BusinessObjectType
(i.e., businessObjectType
is and was null) everything works like a charm.
If the identity had a businessObjectType != null
we get a "Javassist Enhancement failed" Exception:
Javassist Enhancement failed: ch.ethz.id.wai.baseclasses.BusinessObjectType
The error seems to be related to Envers trying to instantiate a BusinessObjectType but I don't really see what the problem could be (Hibernate has no problems with both objects if we don't use an AuditQuery).
The cause of the exception is
java.lang.InstantiationException: ch.ethz.id.wai.baseclasses.BusinessObjectType_$$_javassist_49
with no stack trace.
Any hint on what the problem could be?
La solution
This happens inside the following class JavassistLazyInitializer A Javassist-based lazy initializer proxy.
Without having a look at full source it is difficult to comment but you can try following options.
- Turn off Lazy loading for @ManyToOne relationship [This is a design decision so watch out if it doesn't fit in overall solution]
- Provide a default public constructor for your entity which is causing problem[This is easier]
- turn off reflection optimisation if not really required by setting up
hibernate.bytecode.use_reflection_optimizer
property to false
Let us know if this helps
Autres conseils
To get a more information about the exception, use the debugging facilities of your IDE to set an exception breakpoint for java.lang.InstantiationException
to halt execution when the underlying exception occurs. This should show you the full stack trace, and allow you to inspect all variables on the stack.
If I had to guess, my first suspicion would be that since the association to
BusinessObjectType
is not mapped lazy, plain hibernate doesn't ever try to create a proxy for the class. Envers in contrast appears to do. A proxy is a subclass generated at runtime overriding all public methods. Therefore, neither the class nor any public methods (beside those inherited from Object
) may be declared final
, and a default constructor must be accessible to the subclass.