Could not serialize object cause of HibernateProxy

public class HibernateProxyTypeAdapter extends TypeAdapter<HibernateProxy> {

    public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
        @Override
        @SuppressWarnings("unchecked")
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter(gson) : null);
        }
    };
    private final Gson context;

    private HibernateProxyTypeAdapter(Gson context) {
        this.context = context;
    }

    @Override
    public HibernateProxy read(JsonReader in) throws IOException {
        throw new UnsupportedOperationException("Not supported");
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public void write(JsonWriter out, HibernateProxy value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        // Retrieve the original (not proxy) class
        Class<?> baseType = Hibernate.getClass(value);
        // Get the TypeAdapter of the original class, to delegate the serialization
        TypeAdapter delegate = context.getAdapter(TypeToken.get(baseType));
        // Get a filled instance of the original class
        Object unproxiedValue = ((HibernateProxy) value).getHibernateLazyInitializer()
                .getImplementation();
        // Serialize the value
        delegate.write(out, unproxiedValue);
    }
}

To use it you must first register it:

GsonBuilder b = new GsonBuilder();
...
b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY);
...
Gson gson = b.create();

Notice that this will recursively initialize every proxy you have in the object hierarchy; since however you have to serialize the whole data, you should have done that anyway.

How does this work?

GSON contains a number of TypeAdapterFactory implementations, for various types (primitive types, common types like String or Date, lists, arrays...). Each factory is asked if it is able to serialize a certain Java type (the parameter to create is a TypeToken instead of a Class in order to capture possible information about generic types, which Class does not have). If the factory is able to serialize/deserialize a type, it responds with a TypeAdapter instance; otherwise it responds with null.

HibernateProxyTypeAdapter.FACTORY verifies whether type implements HibernateProxy; in that case, it returns an instance of HibernateProxyTypeAdapter for serialization. The write method is called when an actual object has to be serialized; the adapter extracts the original type of the underlying object, and asks GSON for the standard TypeAdapter for the original type, which generally is a ReflectiveTypeAdapter.

Then it retrieves an instance of the original class, instead of directly using the proxy. This is necessary because ReflectiveTypeAdapter accesses directly to fields, instead of using getters; accessing to the fields of a proxied object does not work, and is a classical Hibernate pitfall.

As a possible performance improvement, the delegate TypeAdapter should be acquired in the create method. I found out that calling getSuperclass() on the proxy Class appears to yield the original base class. The code can then become:

public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
    @Override
    @SuppressWarnings("unchecked")
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        return (HibernateProxy.class.isAssignableFrom(type.getRawType())
                ? (TypeAdapter<T>) new HibernateProxyTypeAdapter((TypeAdapter)gson.getAdapter(TypeToken.get(type.getRawType().getSuperclass())))
     : null);
    }
};
private final TypeAdapter<Object> delegate;

private HibernateProxyTypeAdapter(TypeAdapter<Object> delegate) {
    this.delegate = delegate;
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void write(JsonWriter out, HibernateProxy value) throws IOException {
    if (value == null) {
        out.nullValue();
        return;
    }
    delegate.write(out, ((HibernateProxy) value).getHibernateLazyInitializer()
            .getImplementation());
}

原文档出处:http://stackoverflow.com/questions/13459718/could-not-serialize-object-cause-of-hibernateproxy
时间: 2024-12-28 03:17:03

Could not serialize object cause of HibernateProxy的相关文章

Serialize object graph to XML in .Net

http://coding-time.blogspot.hk/2008/03/serialize-object-graph-to-xml-in-net.html How to serialize any data structure to XML? My first idea was XmlSerializer. But then I found out it had some serious drawbacks. Luckily, there is a better option - NetD

Redis存储Object 和 list&lt;object&gt;

Redis 存储支持的类型没有object ,虽然有支持list,但是只支持List<String> 有两种方法可以实现存储对象和泛型 1.用序列化和反序列化 2.json 序列化工具类,实现序列化和反序列话对象和list集合 package com; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.Object

Java Object JDK序列化总结

Java Object JDK序列化总结 @author ixenos Java序列化是在JDK 1.1中引入的,是Java内核的重要特性之一.Java序列化API允许我们将一个对象转换为流,并通过网络发送,或将其存入文件或数据库以便未来使用,反序列化则是将对象流转换为实际程序中使用的Java对象的过程.Java同步化过程乍看起来很好用,但它会带来一些琐碎的安全性和完整性问题,在文章的后面部分我们会涉及到,以下是本教程涉及的主题. Java序列化接口 使用序列化和serialVersionUID

.Net 4.0 Convert Object to XDocument

将Object转换为XDocment对象 代码如下: C# – Object to XDocument 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Xml.Linq; 6 using System.IO; 7 using System.Xml.Serialization; 8 using System.Xml; 9 10 n

Redis 存储图片 [base64/url/path]vs[object]

一.base64图片编解码 基本流程:从网络获取下载一张图片,然后base64编码,再base64解码,存到本地E盘根目录下. import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLE

JavaScriptSerializer类 对象序列化为JSON,JSON反序列化为对象 。

JavaScriptSerializer 类由异步通信层内部使用,用于序列化和反序列化在浏览器和 Web 服务器之间传递的数据.说白了就是能够直接将一个C#对象传送到前台页面成为javascript对象.要添加System.Web.Extensions.dll的引用.该类位于System.Web.Script.Serialization命名空间下. 一.属性 MaxJsonLength 获取或设置 JavaScriptSerializer 类接受的 JSON 字符串的最大长度. Recursio

Python标准库 (pickle包,cPickle包)

在之前对Python对象的介绍中 (面向对象的基本概念,面向对象的进一步拓展),我提到过Python"一切皆对象"的哲学,在Python中,无论是变量还是函数,都是一个对象.当Python运行时,对象存储在内存中,随时等待系统的调用.然而,内存里的数据会随着计算机关机和消失,如何将对象保存到文件,并储存在硬盘上呢? 计算机的内存中存储的是二进制的序列 (当然,在Linux眼中,是文本流).我们可以直接将某个对象所对应位置的数据抓取下来,转换成文本流 (这个过程叫做serialize),

【C#公共帮助类】JsonHelper 操作帮助类, 以后再也不用满地找Json了,拿来直接用

 四个主要操作类:JsonConverter .JsonHelper .JsonSplit .AjaxResult 一.JsonConverter: 自定义查询对象转换动态类.object动态类转换json包.json转换object动态类.DataReader转换为Json.DataSet转换为Json.DataTable转成Json.Datatable转换为Json .格式化字符型日期型布尔型.过滤特殊字符等 using System; using System.Collections.Ge

Spring3中好用的工具类收集

1) 请求工具类 org.springframework.web.bind.ServletRequestUtils //取请求参数的整数值: public static Integer getIntParameter(ServletRequest request, String name) public static int getIntParameter(ServletRequest request, String name, int defaultVal) -->单个值 public sta