Hibernate Envers и "Javassist Enhancement failed" Исключение

Мы используем Hibernate Envers и имеем следующую ситуацию:

Класс BusinessObjectType и класс Identity со ссылкой на 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;

    […]

}

Затем мы запрашиваем всю версию Identity с помощью:

AuditQuery auditQuery = auditReader.createQuery().forRevisionsOfEntity(
    Identity.class,
    false,
    true );
auditQuery.add( AuditEntity.id().eq( dbid ) );

@SuppressWarnings( "unchecked" )
List< Object[]> history = (List< Object[]>) auditQuery.getResultList();

Если сохраненный идентификатор не имеет BusinessObjectType (т.е. BusinessObjectType is и был null), все работает как шарм.

Если идентификатор имел businessObjectType != null, мы получим "Javassist Enhancement failed" Exception:

Javassist Enhancement failed: ch.ethz.id.wai.baseclasses.BusinessObjectType

Ошибка, похоже, связана с Envers, пытающейся создать экземпляр объекта BusinessObjectType, но я не вижу, что может быть проблемой (у Hibernate нет проблем с обоими объектами, если мы не используем AuditQuery).

Причиной исключения является

java.lang.InstantiationException: ch.ethz.id.wai.baseclasses.BusinessObjectType_$$_javassist_49

без трассировки стека.

Любой намек на то, что проблема может быть?

Ответ 1

Это происходит внутри следующего класса JavassistLazyInitializer Jazassist-based ленивый прокси-сервер инициализации.

Без взгляда на полный источник сложно комментировать, но вы можете попробовать следующие варианты.

  • Отключить Lazy loading для отношений @ManyToOne [ Это дизайнерское решение, поэтому следите, если оно не подходит в общем решении)
  • Предоставить публичный конструктор по умолчанию для вашего объекта, который вызывает проблему [Это проще]
  • отключить оптимизацию отражения, если это действительно не требуется, настроив свойство hibernate.bytecode.use_reflection_optimizer на false

Сообщите нам, если это поможет

Ответ 2

Чтобы получить дополнительную информацию об исключении, используйте средства отладки вашей среды IDE, чтобы установить контрольную точку исключения для java.lang.InstantiationException, чтобы остановить выполнение, когда возникает основное исключение. Это должно показать полную трассировку стека и позволить вам проверять все переменные в стеке.

Если бы я должен был догадаться, мое первое подозрение было бы в том, что, поскольку ассоциация BusinessObjectType не отображается ленивым, простой спящий режим никогда не пытается создать прокси для класса. Кажется, что наоборот. Прокси-сервер - это подкласс, сгенерированный во время выполнения, переопределяя все общедоступные методы. Поэтому ни класс, ни общедоступные методы (помимо тех, которые унаследованы от Object) не могут быть объявлены final, и конструктор по умолчанию должен быть доступен подклассу.