开发者

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();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜