2012-07-12 20 views
14

Estoy escribiendo una función en hibernación para inicializar recursivamente todas las propiedades del objeto recursivamente para que se cargue el gráfico completo del objeto.Inicialización recursiva de Hibernate

tengo dos escenarios complejos donde i necesidad de utilizar este objeto compuesto

1) auto como categoría y la categoría sub ...

@Entity 
public class Category { 

    @Column(nullable = false, length = 50) 
    @NotNull 
    @Size(max = 50, message = "{50}") 
    protected String name; 

    @ManyToOne(targetEntity = Category.class, fetch = FetchType.LAZY, optional = true) 
    private Category parentCategory; 
    } 

2) complejo gráfico de objetos que tiene gran cantidad de objeto a inicializar antes de que pueda ser utilizado.

problema es que no puedo usar la búsqueda ansiosa porque necesito este gráfico de objeto completo solo en casos selectivos, y quiero tener código general para no tener que escribir consultas HQL para objetos.

he escrito algo de código parcial para esto,

public void recursiveInitliaze(Object obj) throws Exception { 
    if(!Hibernate.isInitialized(obj)) 
     Hibernate.initialize(obj); 
    PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
    for (PropertyDescriptor propertyDescriptor : properties) { 
     Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
     if (origProp != null) { 
      this.recursiveInitliaze(origProp); 
     } 
     if (origProp instanceof Collection && origProp != null) {    
      for (Object item : (Collection) origProp) { 
       this.recursiveInitliaze(item); 
      } 
     } 
    } 
} 

pero tiene un problema, que termina en stackoverflow de invocación de método debido a las relaciones bidireccionales. Entonces, ¿cómo detectar que existe una relación bidireccional o hay alguna forma mejor de implementar esto?

Creo que el perfil fetch también puede ayudar, pero aún así quiero intentar implementar esto si es posible, ya que la configuración del perfil de búsqueda en la etapa actual del proyecto es difícil.

Respuesta

7

puede usar Hibernate.initialize() en el objeto para inicializarlo. No estoy seguro si esto cae en cascada. De lo contrario, puede marcar instanceof HibernateProxy, que le otorga una propiedad inicializada.

Actualización: dado que la inicialización no se inicia en cascada, debe atravesar el árbol como lo hace. Use un Hashset para realizar un seguimiento de los objetos que ya procesó.

+0

isInitialised ya he utilizado en la lógica, pero el problema que estoy enfrentando es con relación bidireccional, por ejemplo, si la clase A se asocia con B y ambos contienen referencias entre sí, siempre lo obtendré como propiedad y terminará en una llamada recursiva infinita. –

+0

isInitialised le da verdadero después de que lo haya inicializado una vez y no necesitará realizar una cascada después, ningún bucle infinito. ¿Ha comprobado si initialize() hace lo que quiere? – Firo

+0

sí initialize() solo inicializa el objeto actual y no se conecta en cascada. y no puedo depender de isInitialised porque si tengo una jerarquía de objetos como A contiene B, B contiene C, entonces incluso B se inicializa C podría no ser así, tiene que ir al objeto B encontrar C e inicializar. El problema con mi código es que si C contiene una referencia posterior a B, intenta invocar la función nuevamente. –

5

código completo:

public <T> T recursiveInitliaze(T obj) { 
    Set<Object> dejaVu = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>()); 
    try { 
     recursiveInitliaze(obj, dejaVu); 
    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { 
     ReflectionUtils.handleReflectionException(e); 
    } 
    return obj; 
} 

private void recursiveInitliaze(Object obj, Set<Object> dejaVu) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { 
    if (dejaVu.contains(this)) { 
     return; 
    } else { 
     dejaVu.add(this); 

     if (!Hibernate.isInitialized(obj)) { 
      Hibernate.initialize(obj); 
     } 
     PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
     for (PropertyDescriptor propertyDescriptor : properties) { 
      Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
      if (origProp != null) { 
       this.recursiveInitliaze(origProp, dejaVu); 
      } 
      if (origProp instanceof Collection && origProp != null) { 
       for (Object item : (Collection<?>) origProp) { 
        this.recursiveInitliaze(item, dejaVu); 
       } 
      } 
     } 
    } 
} 

Código de ReflectionUtils:

/** 
* Handle the given reflection exception. Should only be called if no 
* checked exception is expected to be thrown by the target method. 
* <p>Throws the underlying RuntimeException or Error in case of an 
* InvocationTargetException with such a root cause. Throws an 
* IllegalStateException with an appropriate message else. 
* @param ex the reflection exception to handle 
*/ 
public static void handleReflectionException(Exception ex) { 
    if (ex instanceof NoSuchMethodException) { 
     throw new IllegalStateException("Method not found: " + ex.getMessage()); 
    } 
    if (ex instanceof IllegalAccessException) { 
     throw new IllegalStateException("Could not access method: " + ex.getMessage()); 
    } 
    if (ex instanceof InvocationTargetException) { 
     handleInvocationTargetException((InvocationTargetException) ex); 
    } 
    if (ex instanceof RuntimeException) { 
     throw (RuntimeException) ex; 
    } 
    throw new UndeclaredThrowableException(ex); 
}