You can do without manually deleting everyone using a custom TypeAdapter . Something like that:
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; }
To use it, you must first register it:
GsonBuilder b = new GsonBuilder(); ... b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY); ... Gson gson = b.create();
Note that this will recursively initialize every proxy server that you have in the hierarchy of objects; since, nevertheless, you need to serialize all the data, you still had to do it.
How it works?
GSON contains a number of implementations of TypeAdapterFactory for different types (primitive types, generic types like String or Date , lists, arrays ...). Each factory is asked if it can serialize a specific Java type (the create parameter is a TypeToken instead of a Class to capture possible information about common types that a Class does not have). If the factory is able to serialize / deserialize the type, it responds with an instance of the TypeAdapter ; otherwise, it answers null .
HibernateProxyTypeAdapter.FACTORY checks if the HibernateProxy type implements; in this case, it returns an instance of HibernateProxyTypeAdapter for serialization. The write method is called when the actual object needs to be serialized; the adapter retrieves the source type of the base object and queries GSON for the standard TypeAdapter for the source type, which is usually the ReflectiveTypeAdapter .
It then retrieves an instance of the source class instead of using the proxy directly. This is necessary because the ReflectiveTypeAdapter accesses the fields directly instead of using getters; Access to the proxy object fields does not work and is a classic Hibernate pitfall .
As a possible performance improvement, a TypeAdapter delegate should be acquired in the create method. I found out that calling getSuperclass() on the Class proxy seems to give the original base class. Then the code can 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()); }