2010-10-14 12 views
34

Es posible escribir un deserializador json en gson que invoca primero el comportamiento predeterminado y luego puedo hacer un procesamiento posterior en mi objeto. Por ejemplo:gson invocando la deserialización estándar en el deserializador personalizado

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

estoy usando GSON 1.3 (no puedo usar cualquier otra versión, ya que sólo puedo utilizar las versiones en el diccionario de la empresa)

gracias

+1

cuenta de que hay un problema general http://code.google.com/p/google-gson/issues/detail?id=43 – Asim

+3

Buen trabajo Asim. ¿Puede publicar una respuesta a la pregunta usted mismo y luego aceptar esa respuesta para que podamos cerrar esta pregunta? Además, debe aceptar respuestas a preguntas anteriores si resuelven su problema. – Zecas

+0

@Kev. Vuelve a abrir esta pregunta. Obviamente, fue importante para las 8 personas que le dieron un voto positivo, incluyéndome a mí (la novena persona). – Guy

Respuesta

3

Puede hacerlo mediante la implementación la TypeAdapterFactory personalizada para su objeto (digamos CustomClass.class) se deserializará como se muestra a continuación.

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 
      } 
     }; 
    } 
    } 

Y luego registrarla con Gson como

Gson gson = new GsonBuilder().registerTypeAdapter(CustomClass.class,new CustomTypeAdapterFactory()).create(); 
+10

¿Y de dónde vienen las variables 'delegate' y' elementAdapter'? – Flawyte

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

Salida http://gsonfire.io

Es una biblioteca que hizo que se extiende Gson para manejar casos como el Post-serialización y Post-deserialización

También tiene muchas otras características interesantes que he necesitado durante tim e con Gson.

0

Aquí está la implementación completa basada en la respuesta incompleta proporcionada por @ user1556622 y discusión en code.google.com/p/google-gson/issues/detail?id=43.

Como resultado, podemos serializar la lista de objetos abstractos Field y deserializarla sin problemas en la implementación concreta de Field y su profundidad jerárquica.

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); 
     } 
    } 
} 

Registro de fábrica:

Gson gson = new GsonBuilder() 
       .registerTypeAdapterFactory(new FieldTypeAdapterFactory()) 
       .create(); 
0
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; 
} 
Cuestiones relacionadas