2013-08-01 9 views
13

Ho riscontrato un problema nella registrazione di più TypeAdapters con GsonBuilder. Sembra che solo uno si spari e non prende mai in considerazione il secondo. Se lo faccio da solo, sembra funzionare bene. Ma ho bisogno che funzionino con entrambi e sembra che stia facendo qualcosa di sbagliato. Inoltre sto attualmente utilizzando GSON v2.2.4.La registrazione di più adattatori con GSON non funziona

Zip oggetto forma semplice:

public class Zip { 

    private String zipCode; 
    private String city; 
    private String state; 

    public Zip(){}            
} 

ZipSerializer:

public class ZipSerializer implements JsonSerializer<Zip>{ 

    @Override 
    public JsonElement serialize(Zip obj, Type type, JsonSerializationContext jsc) { 
     Gson gson = new Gson(); 
     JsonObject jObj = (JsonObject)gson.toJsonTree(obj); 
     jObj.remove("state");   
     return jObj; 
    } 

} 

JsonResponse oggetto forma semplice:

public class JsonResponse { 

    private String jsonrpc = "2.0"; 
    private Object result = null; 
    private String id = null; 

    public JsonResponse(){} 

} 

JsonResponseSerializer:

public class JsonResponseSerializer implements JsonSerializer<JsonResponse> { 

    @Override 
    public JsonElement serialize(JsonResponse obj, Type type, JsonSerializationContext jsc) { 
     Gson gson = new Gson(); 
     JsonObject jObj = (JsonObject)gson.toJsonTree(obj); 
     jObj.remove("id"); 

     return jObj; 
    } 

} 

test Esempio:

public class Test { 

    public static void main(String[] args) { 
     Zip zip = new Zip(); 
     zip.setCity("testcity"); 
     zip.setState("OH"); 
     zip.setZipCode("12345"); 

     JsonResponse resp = new JsonResponse(); 
     resp.setId("1"); 
     resp.setResult(zip); 
     resp.setJsonrpc("2.0"); 

     Gson gson1 = new GsonBuilder() 
     .registerTypeAdapter(JsonResponse.class, new JsonResponseSerializer()) 
     .registerTypeAdapter(Zip.class, new ZipSerializer()) 
     .setPrettyPrinting() 
     .create(); 


     String json = gson1.toJson(resp); 
     System.out.println(json);    

    } 

} 

uscita:

{ 
    "jsonrpc": "2.0", 
    "result": { 
    "zipCode": "12345", 
    "city": "testcity", 
    "state": "OH" 
    } 
} 

Previsto in uscita: (Avviso ZipSerializer non ha sparare)

{ 
    "jsonrpc": "2.0", 
    "result": { 
    "zipCode": "12345", 
    "city": "testcity" 
    } 
} 

ho simpled lungo il banco di prova per questo. So che posso usare exclusionStrategy in questo esempio per ottenere risultati, ma il vero problema è molto più complesso e questo è stato il modo migliore per me di ritrarre e replicare il mio problema.

Grazie

< ---------------------------- SOLUZIONE ----------- -------------------->

Sono riuscito a leggere Gson custom seralizer for one variable (of many) in an object using TypeAdapter e mi ha aiutato molto.

Ho creato una base customTypeAdapterFactory e l'ho estesa per ogni classe che necessitava di serializzazione speciale.

CustomizedTypeAdapterFactory

public abstract class CustomizedTypeAdapterFactory<C> implements TypeAdapterFactory { 

    private final Class<C> customizedClass; 

    public CustomizedTypeAdapterFactory(Class<C> customizedClass) { 
     this.customizedClass = customizedClass; 
    } 

    @SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal 
    public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 
     return type.getRawType() == customizedClass 
       ? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type) 
       : null; 
    } 

    private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) { 
     final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type); 
     final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class); 

     return new TypeAdapter<C>() { 

      @Override public void write(JsonWriter out, C value) throws IOException {    
       JsonElement tree = delegate.toJsonTree(value); 
       beforeWrite(value, tree); 
       elementAdapter.write(out, tree); 
      } 


      @Override public C read(JsonReader in) throws IOException { 
       JsonElement tree = elementAdapter.read(in); 
       afterRead(tree); 
       return delegate.fromJsonTree(tree); 
      } 
     }; 
    } 

    /** 
    * Override this to muck with {@code toSerialize} before it is written to 
    * the outgoing JSON stream. 
    */ 
    protected void beforeWrite(C source, JsonElement toSerialize) { 
    } 

    /** 
    * Override this to muck with {@code deserialized} before it parsed into 
    * the application type. 
    */ 
    protected void afterRead(JsonElement deserialized) { 
    } 
} 

ZipTypeAdapterFactory (fatto questo con JsonResponseTypeAdapterFactory)

public class ZipTypeAdapterFactory extends CustomizedTypeAdapterFactory<Zip> { 

    ZipTypeAdapterFactory() { 
     super(Zip.class); 
    } 

    @Override 
    protected void beforeWrite(Zip source, JsonElement toSerialize) { 
     JsonObject obj = (JsonObject) toSerialize; 
     obj.remove("state"); 
    } 

} 

Codice di prova:

Gson gson1 = new GsonBuilder() 
     .registerTypeAdapterFactory(new JsonResponseTypeAdapterFactory())  
     .registerTypeAdapterFactory(new ZipTypeAdapterFactory()) 
     .setPrettyPrinting() 
     .create(); 


     String json = gson1.toJson(resp); 
     System.out.println(json); 

Grazie a tutti per l'aiuto.

risposta

4

Il problema è nel tuo JsonResponseSerializer. Si crea una nuova istanza di Gson, quindi su questa nuova istanza ZipSerializer non è registrata. Ecco perché il tuo secondo serializzatore non viene mai chiamato.

Se si desidera ottenere la delega e la serializzazione complessa, consultare TypeAdapterFactory.

Come hai detto, se desideri semplicemente filtrare i campi dalla serializzazione definisci uno ExclusionStrategy.

+0

Grazie per la spiegazione. Devo aver frainteso il modo in cui ha funzionato JsonSerializer. Come ho detto, ho reso il mio esempio probabilmente l'esempio di base che potevo replicare il problema e dove sono effettivamente in Exclusion Strategies probabilmente non è la strada da percorrere. Analizzerò TypeAdapterFactory che al momento è nuovo per me con poca comprensione. – dayv2005

+0

Puoi guardare qui se vuoi vedere un esempio di codice con delega: http://stackoverflow.com/questions/17909602/deserialize-to-type-at-runtime/17925280#17925280. – PomPom

+0

e chiudi il post se hai la tua risposta;) – PomPom

Problemi correlati