14

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?

Matteo
  • 14,696
  • 9
  • 68
  • 106

2 Answers2

21

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

Manish Singh
  • 3,463
  • 22
  • 21
  • Fetching is the default: SELECT. The constructor was not public. Thanks. I still have to understand why Envers wants to instantiate more than plain Hibernate. – Matteo Sep 11 '11 at 07:28
  • why must the default constructor be `public`? I see a potentially conflicting answer [here](http://stackoverflow.com/questions/2935826/why-does-hibernate-require-no-argument-constructor#comment9688725_2971717) – Kevin Meredith Dec 04 '14 at 21:41
1

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.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • I have the same suspect: Envers tries to fetch more (otherwise I would not have the error). One problem is: why? How can I avoid it? On the other hand BusinessObjectType has a default public constructor and no final fields. With plain Envers it can be fetched without any problems. – Matteo Sep 11 '11 at 06:54
  • ... and no final methods either? I don't know enough about the internals of Envers to guess further. That's why I would start debugging to get more information. – meriton Sep 11 '11 at 07:00
  • Actually I didn't notice that during the last changes to test I re-made the constructor private. By the way: with a public constructor finals methods seem to work. Thanks! – Matteo Sep 11 '11 at 07:30
  • I awarded the bounty to user3965072 since he was first ... I didn't have the possibility to test right after his answer (week-end :-) – Matteo Sep 11 '11 at 07:31