gson invoking standard deserialization in custom deserializer
Is it possible to write a json deserializer in gson that invokes the default behaviour first and then i can do some post processi开发者_StackOverflow中文版ng on my object. For example:
public class FooDeserializer implements JsonDeserializer<Foo> {
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Foo foo = context.deserialize(json, typeOfT);//Standard deserialization call?????
foo.doSomething();
return foo();
}
}
I am using gson 1.3 (I cannot use any other version as i can only use the versions in the corporate repository)
thanks
You can do that by implementing custom TypeAdapterFactory for your object (say CustomClass.class) to be deserialized as below.
public class CustomTypeAdapterFactory implements TypeAdapterFactory {
public final TypeAdapter create(Gson gson, TypeToken type) {
return new TypeAdapter() {
@Override
public void write(JsonWriter out, Object value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
//add code for writing object
}
@Override
public Object read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
//Add code for reading object
}
};
}
}
And then registering it with Gson as
Gson gson = new GsonBuilder().registerTypeAdapter(CustomClass.class,new CustomTypeAdapterFactory()).create();
public class FooDeserializer implements JsonDeserializer<Foo> {
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Foo foo=new Gson().fromJson(json, Foo.class); // use default Gson object
foo.doSomething();
return foo;
}
Check out http://gsonfire.io
It's a library I made that extends Gson to handle cases like Post-serialization and Post-deserialization
Also it has many other cool features that I've needed over time with Gson.
public class YourDeserializer<Foo> extends FooDeserializer<Foo>
{
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Foo foo = super.deserialize(json, typeOfT,context);
foo.doSomething(); //put logic
return foo();
}
}
Here's full implementation based on incomplete answer provided by @user1556622 and discussion in code.google.com/p/google-gson/issues/detail?id=43.
As a result we can serialize list of abstract Field
objects and smoothly deserialize it independent on concrete implementation of specific Field
and its hierarchy depth.
class MyClass { //class which we would like to serialiaze/deserialize
List<Field> fields; //field is an hierarchy of classes
}
/**
* Purpose of this adapter is simple:
* 1) put during serialization in all Field objects additional property describing class
* 2) during deserialization invoke (based on class info) necessary deserializer to create class
*/
public class FieldTypeAdapterFactory implements TypeAdapterFactory {
private static final String CLASS_META_KEY="clz";
Gson gson;
TypeToken<?> type;
TypeAdapter<Field> fieldAdapter;
TypeAdapter<JsonElement> elementAdapter;
TypeAdapterFactory taf;
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!Field.class.isAssignableFrom(type.getRawType()))
return null; // this class only serializes 'Field' and its subtypes
this.type=type;
this.gson=gson;
this.taf=this;
fieldAdapter = gson.getDelegateAdapter(taf, TypeToken.get(Field.class));
elementAdapter = gson.getAdapter(JsonElement.class);
TypeAdapter<T> result = new FieldTypeAdapter<T>();
result.nullSafe();
return result;
}
class FieldTypeAdapter<T> extends TypeAdapter<T> {
public FieldTypeAdapter() {
}
@Override
public void write(JsonWriter out, Object value) throws IOException {
if(value instanceof Field) {
JsonObject object = fieldAdapter.toJsonTree((Field )value).getAsJsonObject();
object.addProperty(CLASS_META_KEY, value.getClass().getCanonicalName());
elementAdapter.write(out, object);
}
else {
elementAdapter.write(out, (JsonElement) value);
}
}
@Override
public T read(JsonReader in) throws IOException {
JsonObject object = elementAdapter.read(in).getAsJsonObject();
if (object.has(CLASS_META_KEY)) {
String className=object.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
TypeAdapter<?> adapter = gson.getDelegateAdapter(taf, TypeToken.get(clz));
return (T) adapter.fromJsonTree(object);
}
catch (Exception e) {
return (T )fieldAdapter.fromJsonTree(object);
}
}
else
return (T )elementAdapter.fromJsonTree(object);
}
}
}
Registration of factory:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new FieldTypeAdapterFactory())
.create();
精彩评论