Hessian序列化Hibernate的延迟加载Set等集合的解决方案
假如有如下类,Customer和Order,在使用Hessian序列化Customer时,如果orders延迟加载,并且序列化时Hibernate的session已经关闭,则会抛出Hibernate的LazyInitializationException.
@Entity public class Customer implements java.io.Serializable { @Id private long id; private String name; //一对多,延迟加载 @OneToMany(fetch=FetchType.LAZY) @JoinColumn(name="CUSTOMER_ID") private Set<Order> orders; ........... @Entity public class Order implements java.io.Serializable{ @Id private long id; .......
该Set为Hibernate的PersistentSet,是Hibernate的PersistentCollection的子类。原因是Hessian序列化时,会调用PersistentSet的方法导致Hibernate从session里加载数据,如果session已经关闭,就会抛出异常,导致序列化出错。不仅Set会出现,PersistentCollection的其他子类也会出现该现象,如PersistentList,PersistentBag,PersistentMap等。使用JDK的序列化不会出现该现象。
解决方案如下,可以为Hibernate的PersistentColletion定制一个Serializer,代码如下:
import com.caucho.hessian.io.AbstractHessianOutput; import com.caucho.hessian.io.AbstractSerializer; import com.caucho.hessian.io.CollectionSerializer; import com.caucho.hessian.io.MapSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import org.hibernate.Hibernate; import org.hibernate.collection.PersistentMap; public class HibernateSerializer extends AbstractSerializer { CollectionSerializer collectionSeiralizer = new CollectionSerializer(); MapSerializer mapSerializer = new MapSerializer(); @Override public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { boolean init = Hibernate.isInitialized(obj); if (init) { out.writeObject(obj); out.flush(); return; } if (PersistentMap.class.isAssignableFrom(obj.getClass())) { //将没有初始化的Map序列化空的HashMap mapSerializer.writeObject(new HashMap(), out); } else { //将没有初始化的List,Set等序列化为空的ArrayList collectionSeiralizer.writeObject(new ArrayList(), out); } } }
同时还需要定制一个序列化工厂SerializerFactory,代码如下:
import com.caucho.hessian.io.HessianProtocolException; import com.caucho.hessian.io.Serializer; import com.caucho.hessian.io.SerializerFactory; import org.hibernate.collection.PersistentCollection; public class HibernateSerializerFactory extends SerializerFactory { @Override public Serializer getSerializer(Class cl) throws HessianProtocolException { //Hibernate的集合API使用为HibernateSerializer序列化 if (PersistentCollection.class.isAssignableFrom(cl)) { return new HibernateSerializer(); } return super.getSerializer(cl); } }
可以调用HessianServlet.getSerializerFactory().addFactory()添加HibernateSerializerFactory来使用该HibernateSerializer序列化Hibernate的PersistentCollection.
或者写一个serializers文件放到classpath的META-INF/hessian/目录下,该文件的内容为
org.hibernate.collection.PersistentCollection=HibernateSerializer