2008-11-30 13 views
5

He estado enfrentando este problema en el que los objetos de hibernación en la serialización producen inesperados xmls que contienen todo el código instrumentado de Hibernate.Problema con la serialización de objetos Hibernate usando XStream

Limpiamos el objeto antes de serializar el objeto.

Pero, ¿hay una opción estándar disponible para serializar el objeto directamente?

+0

¿Quizás podría mostrar cómo es XML? –

Respuesta

3

No he usado XStream anteriormente, pero he serializado entidades gestionadas por Hibernate. No es divertido

Hay dos grandes problemas:

  • La carga diferida;
  • Relaciones uno a muchos.

Lo primero es obvio: necesita los datos reales para serializar. Esto último es menos importante: cualquier relación de uno a muchos que declare en contra de las interfaces de recopilación (por ej., Set<T>) quedará bloqueada por las propias implementaciones de la colección de Hibernate (¡no se puede serializar!). Puede ser que las clases de Hibernate sangren en tus objetos.

Terminé de escribir código de reflexión (en realidad introspectiva) que hizo esto:

  1. Con la sesión abierta, tocó todo el gráfico de objetos para forzar a cargar cualquier entidad sin carga;
  2. Cerró la sesión de Hibernate (incluida cualquier transacción que implique su conexión);
  3. Cambié el gráfico del objeto, reemplazando cualquier lista, conjunto o mapa con instancias de ArrayList, HashSet o HashMap (colecciones conocidas-serializables).

Tenga en cuenta que el paso 2 es importante - si reemplaza las colecciones antes de cerrar la sesión, Hibernate sólo hay que poner sus propias colecciones de vuelta de una estrecha ...

Editar: @ cliff.meyers detecté un detalle de la implementación que olvidé mencionar: si hace esto, debe limitar la caminata del gráfico de objetos solo a sus propias entidades, y observar las rutas de referencia circulares (por ejemplo: almacenando en el caché referencias a objetos que ya ha recorrido).

1

Hay algo de información sobre esto (y código de ejemplo) a lo largo de la Codehaus JIRA:

http://jira.codehaus.org/browse/XSTR-226

Escribimos algunas herramientas de evitar este tipo de problema para un montón de otras implementaciones de comunicación remota (Eje 1, Blaze DS, etc.). Lo que hicimos fue muy similar a la solución de Dan, aunque agregamos la capacidad de declarar qué rutas de objetos caminar y cuáles "recortar" porque en muchas situaciones no estábamos interesados ​​en todos los datos; también habría provocado serios problemas con el problema "n + 1 selecciona" que ocurre miles de veces. :) Creo que implementar un convertidor XStream sería el enfoque óptimo, ya que solo tendrías que recorrer el gráfico del objeto una vez. Si configura FlushMode.MANUAL en su sesión, también debería poder modificar el gráfico de objetos a medida que avanza sin que Hibernate haga algo desagradable. Use esto con precaución, ya que es una técnica un tanto avanzada.

+0

Whoops, se olvidó de mencionar inicialmente los tipos de objetos limitantes para descender a (su sintaxis snip) - gracias por la corrección ... –

3

He encontrado una solución bastante suficiente. En mi aplicación, solo PersistentSets estaba arruinando XML generado por XStream. Así que he añadido otro convertidor a xstream (que funciona con Hibernate Sesión abierta y objetos vivos):

XStream xs = new XStream(); 
xs.registerConverter(new CollectionConverter(xs.getMapper()) { 
    @Override 
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { 
     org.hibernate.collection.PersistentSet ps = (PersistentSet) source; 
     super.marshal(new HashSet(ps), writer, context); 
    } 

    @Override 
    public boolean canConvert(Class type) { 
     return type.isAssignableFrom(org.hibernate.collection.PersistentSet.class); 
    } 
}, XStream.PRIORITY_VERY_HIGH); 
String s = xs.toXML(processInstance); 

El XML serializado se parece a continuación:

<processLogs class="org.hibernate.collection.PersistentSet"> 
    <pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog> 
     <id>813017</id> 
     <entryDate> 
     <time>1310832421216</time> 
     <timezone>GMT</timezone> 
     </entryDate> 
     <eventI18NKey>process.log.action-performed</eventI18NKey> 
     <additionalInfo>Wydrukuj wniosek</additionalInfo> 
     <logValue>GENERATE_APPLICATION</logValue> 
     <logType>PERFORM_ACTION</logType> 
     <state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[8]"/> 
     <processInstance reference="../../.."/> 
     <user reference="../../../creator"/> 
    </pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog> 
    <pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog> 
     <id>808211</id> 
     <entryDate> 
     <time>1310828206169</time> 
     <timezone>GMT</timezone> 
     </entryDate> 
     <eventI18NKey>process.log.action-performed</eventI18NKey> 
     <additionalInfo>Zaakceptuj</additionalInfo> 
     <logValue>ACCEPT</logValue> 
     <logType>PERFORM_ACTION</logType> 
     <state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[4]"/> 
     <processInstance reference="../../.."/> 
     <user reference="../../../creator"/> 
    </pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog> 

En mi caso, el atributo de clase no era importante, por lo que he ignorado su valor. Por supuesto, puedes jugar con eso.

+0

+1 Muy útil, gracias! Mi próximo problema es un PersistentSet envuelto en UnmodifiableSet que, desagradablemente, no es una clase visible: -/ – Rup

+0

Para suprimir el atributo de clase, creo que debes implementar un Mapper personalizado que devuelva serializedClass (PersistentSet.class) == HashSet .clase. Pero parece que eso es una gran cantidad de trabajo para configurar. – Rup

1

no lo ha usado, pero xstream-for-beans parece encajar (citando):

Este proyecto permite la implementación de creadores de mapas y convertidores que mejoran xstream en los aspectos siguientes:

  1. objetos serializar ya que están expuestos por getters y setters. Las características de XStream disponibles para los campos deben funcionar para las propiedades definidas para las propiedades getter/setter.
  2. serialización de desinfección de objetos gestionados: omite automáticamente los campos irrelevantes y la clase información.
  3. Manejar campos "fuera de línea" y objetos proxy.

me escribió una vez personalizados xstream Converter s para hacer frente a este problema, como parte de un proyecto de código cerrado por desgracia. xstream-for-beans lidia con los mismos problemas, vale la pena intentarlo.

He utilizado la utilidad Pojoizer de Terracotta con éxito en el pasado, pero no creo que ya se mantenga.

Cuestiones relacionadas