2011-09-01 18 views
10

Estamos utilizando Hibernate Envers y tenemos la siguiente situación:Hibernate Envers y "Javassist Mejora falló" Excepción

Una clase BusinessObjectType y una clase Identity con una referencia a 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; 

    […] 

} 

A continuación, consulta para toda la versión de identidad con:

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

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

Si la identidad almacenada no tiene un BusinessObjectType (es decir, businessObjectType es y fue nulo) todo funciona como un amuleto.

Si la identidad tenía una businessObjectType != null obtenemos un "Javassist Mejora fallido" Excepción:

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

El error parece estar relacionada con Envers tratando de crear instancias de un BusinessObjectType pero yo no veo cuál es el problema podría ser (Hibernate no tiene problemas con ambos objetos si no usamos AuditQuery).

La causa de la excepción es

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

sin seguimiento de la pila.

¿Alguna pista sobre cuál podría ser el problema?

Respuesta

14

Esto ocurre dentro de la siguiente clase JavassistLazyInitializer Un proxy de iniciador perezoso basado en Javasist.

Sin echarle un vistazo al código fuente completo es difícil hacer comentarios, pero puedes probar las siguientes opciones.

  • Desactive la carga diferida para la relación @ManyToOne [Esta es una decisión de diseño así que ten cuidado si no encaja en la solución global]
  • proporcionar un constructor público predeterminado para su entidad que está causando un problema [esto es más fácil]
  • desactivar la optimización de reflexión si realmente no es requerido por la creación de hibernate.bytecode.use_reflection_optimizer propiedad en false

hacernos saber si esto ayuda

+0

La obtención es el valor predeterminado: SELECCIONAR. El constructor no era público Gracias.Todavía tengo que entender por qué Envers quiere crear una instancia más que simple Hibernate. – Matteo

+0

¿por qué el constructor predeterminado debe ser 'public'? Veo una respuesta potencialmente conflictiva [aquí] (http://stackoverflow.com/questions/2935826/why-does-hibernate-require-no-argument-constructor#comment9688725_2971717) –

1

Para obtener más información sobre la excepción, utilice las funciones de depuración de su IDE para establecer un punto de interrupción de excepción para java.lang.InstantiationException para detener la ejecución cuando se produce la excepción subyacente. Esto debería mostrarle la traza completa de la pila y le permitirá inspeccionar todas las variables en la pila.

Si tuviera que adivinar, mi primera sospecha sería que, dado que la asociación a BusinessObjectType no está asignada como floja, hibernación simple nunca intenta crear un proxy para la clase. Envers en contraste parece hacer. Un proxy es una subclase generada en tiempo de ejecución anulando todos los métodos públicos. Por lo tanto, ni la clase ni los métodos públicos (además de los heredados de Object) pueden declararse final, y la subclase debe tener acceso a un constructor predeterminado.

+0

Tengo el mismo sospechoso: Envers intenta buscar más (de lo contrario, no tendría el error). Un problema es: ¿por qué? ¿Cómo puedo evitarlo? Por otro lado, BusinessObjectType tiene un constructor público predeterminado y no campos finales. Con Envers simple, puede buscarse sin ningún problema. – Matteo

+0

... y tampoco hay métodos finales? No sé lo suficiente sobre los aspectos internos de Envers para adivinar más. Es por eso que comenzaría a depurar para obtener más información. – meriton

+0

En realidad, no me di cuenta de que durante los últimos cambios para probar rehice el constructor privado. Por cierto: con un constructor público, los métodos finales parecen funcionar. ¡Gracias! – Matteo

Cuestiones relacionadas