2012-09-25 15 views
12

AFAIK la personalizzazione più flessibile di GSON è possibile tramite TypeAdapterFactory, tuttavia potrebbe essere inutilmente complicata. Mi costringe a scrivere per ogni classe gestita sia read e write, mentre a volte solo un metodo è davvero necessario. Inoltre, a volte uno JsonSerializer e/o JsonDeserializer era molto più facile da scrivere, ad es. like here. Questo mi porta a queste domande:Uso più semplice di TypeAdapterFactory

  • È possibile scrivere un TypeAdapter che semplicemente delega uno dei suoi metodi (ad esempio la scrittura di ImmutableList alla scrittura di List)?
  • È possibile utilizzare in qualche modo JsonSerializer e/o JsonDeserializer insieme allo TypeAdapterFactory? In alternativa, c'è una fabbrica per loro?

risposta

16

È possibile creare un TypeAdapter che delega uno dei suoi metodi. Questo caso d'uso è una parte importante dell'API e c'è un metodo getDelegateAdapter() proprio per questo scopo. Passa al numero this come primo argomento a getDelegateAdapter che restituirà l'adattatore che ha la precedenza dopo il factory corrente.

TypeAdapterFactory immutableListFactory = new TypeAdapterFactory() { 
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 
    if (!(type.getType() instanceof ParameterizedType) 
     || !type.getRawType().equals(ImmutableList.class)) { 
     return null; 
    } 

    ParameterizedType parameterizedType = (ParameterizedType) type.getType(); 
    TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); 
    TypeAdapter<?> elementAdapter = gson.getAdapter(
     TypeToken.get(parameterizedType.getActualTypeArguments()[0])); 
    return new ImmutableListAdapter(delegate, elementAdapter); 
    } 

    class ImmutableListAdapter<E> extends TypeAdapter<ImmutableList<E>> { 
    private TypeAdapter<List<E>> delegate; 
    private TypeAdapter<E> element; 

    ImmutableListAdapter(TypeAdapter<List<E>> delegate, TypeAdapter<E> element) { 
     this.delegate = delegate; 
     this.element = element; 
    } 

    @Override public void write(JsonWriter out, ImmutableList<E> value) throws IOException { 
     delegate.write(out, value); 
    } 

    @Override public ImmutableList<E> read(JsonReader in) throws IOException { 
     if (in.peek() == JsonToken.NULL) { 
     in.nextNull(); 
     return null; 
     } 
     ImmutableList.Builder<E> builder = ImmutableList.builder(); 
     in.beginArray(); 
     while (in.hasNext()) { 
     builder.add(element.read(in)); 
     } 
     in.endArray(); 
     return builder.build(); 
    } 
    } 
}; 

È possibile combinare JsonSerializer/JsonDeserializer con TypeAdapterFactory, ma non direttamente. Il modo più semplice è richiamare in Gson per serializzare i valori figlio nella tua classe. In questo esempio ci piacerebbe cambiare il ciclo interno a questo:

 while (in.hasNext()) { 
     builder.add(gson.<E>fromJson(in, elementType)); 
     } 

La differenza principale tra JsonSerializer/JsonDeserializer e TypeAdapter è quante fasi ci vuole per andare da JSON al modello a oggetti. Con JsonSerializer/JsonDeserializer gli oggetti vengono prima convertiti nel modello DOM di Gson (JsonElement ecc.) E quindi convertiti nel modello a oggetti. Con TypeAdapter, il passaggio intermedio viene saltato.

Questo rende il codice dell'adattatore di tipo un po 'più complicato da leggere e scrivere, quindi dovresti preferirlo solo per il codice ottimizzato.

+1

Questa è una grande risposta. Uno dei cento migliori che ho letto su questo sito nel corso degli anni. Grazie per aver dedicato del tempo per fornire un esempio realistico! Questa risposta ha modificato da sola la mia visione di Gson. – kevinarpe

Problemi correlati