Buscar este blog

martes, 9 de diciembre de 2014

Hibernate proxy to real object - Hibernate proxy to java POJO

Objetivo

Convertir un objeto persistente, recuperado de base de datos con Hibernate, en un POJO java.
Los objetos Hibernate realmente son proxys que se utilizan, por ejemplo, para la inicialización de cargas vagas.
Cuando se tiene una lista dentro de un objeto de Hibernate, esta lista es un PersistentBag que, en el momento de acceder a ella por primera vez, accede a base de datos para cargarla.
En algunas ocasiones se necesita eliminar la "naturaleza de Hibernate" de un objeto, para quitar esos proxys y convertirlos en objetos reales. Así, a la hora de devolver un objeto en un servicio web o hacia la vista sería conveniente trabajar siempre con POJOs.

Solución

Crear un aspecto que intercepte las salidas de los DAOs y ponga a null los proxys no inicializados
En este código a los DAOs se les llama Fachada.

El aspecto inspecciona por reflexión el objeto devuelto. Revista todas sus propiedades y, si alguna no está inicializada (Hibernate.isInitialized) la setea a null.

Código fuente del aspecto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.lang.reflect.Field;
import java.util.Collection;

import org.aspectj.lang.ProceedingJoinPoint;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Aspecto que elmina la naturaleza de hibernate de un objeto. Se ejectua
 * después del retorno de las fachadas e inspecciona los objetos devueltos
 * convirtiendo los proxys de Hibernate en null.
 *
 * @author Sisifo
 *
 */
public class EliminaHibernateProxysAspect {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    public Object eliminarHibernateProxysAround(final ProceedingJoinPoint pjp) throws Throwable {
        final Object retVal = pjp.proceed();
        inicializarSiEsNecesario(retVal);
        return retVal;
    }

    @SuppressWarnings("rawtypes")
    private Object inicializarSiEsNecesario(Object object) {
        if (object == null) {
            return null;
        }

        if (!Hibernate.isInitialized(object)) {
            return null;
        } else {
            if (object instanceof Collection) {
                return inicializarColeccion((Collection) object);
            } else {
                return inicializarPropiedadesObjeto(object);
            }
        }

    }


    @SuppressWarnings("rawtypes")
    private Collection inicializarColeccion(Collection coleccion) {
        for (Object object : coleccion) {
            inicializarSiEsNecesario(object);
        }

        return coleccion;
    }

    private Object inicializarPropiedadesObjeto(Object object) {
        for (Field field : object.getClass().getDeclaredFields()) {
            if (fieldEsSusceptibleDeInicializarse(field)) {
                field.setAccessible(true);
                try {
                    field.set(object, inicializarSiEsNecesario(field.get(object)));
                } catch (final Exception e) {
                    logger.error("Se ha producido un error al acceder al campo {} del objeto {}", new Object[] { field,
                            object }, e);
                    throw new RuntimeException("Error al acceder a campo", e);
                }
            }
        }

        return object;
    }

    private boolean fieldEsSusceptibleDeInicializarse(final Field field) {
        if (Collection.class.isAssignableFrom(field.getType())) {
            return true;
        }

        if (!claseEsDeTipoBasico(field.getType()) && !clasePertenceALaEspecificiacionJava(field.getType())) {
            return true;
        }

        return false;
    }

    private boolean clasePertenceALaEspecificiacionJava(final Class<?> clase) {
        final String clasePropiedad = clase.getCanonicalName();
        if (clasePropiedad.startsWith("java.") || clasePropiedad.startsWith("javax.")) {
            return true;
        }
        return false;
    }

    private boolean claseEsDeTipoBasico(final Class<?> clase) {
        if (clase.isEnum() || clase.isPrimitive()) {
            return true;
        }
        return false;
    }
}

Fichero de cofiguración aop:


1
2
3
4
5
6
7
8
9
<bean id="eliminaHibernateProxysAspectImpl" class="es.sisifo.simplearchetype.persistencia.aop.EliminaHibernateProxysAspect"/>

<aop:config>
   <aop:pointcut id="fachadePointcut"     expression="execution(* es.sisifo..persistencia..*FacadeImpl.*(..))"/>

  <aop:aspect id="eliminaHibernateProxysAspect" ref="eliminaHibernateProxysAspectImpl">      
    <aop:around pointcut-ref="fachadePointcut" method="eliminarHibernateProxysAround"/>            
 </aop:aspect>           
</aop:config>

No hay comentarios:

Publicar un comentario