2011-10-09 16 views
11

Sto usando alcune collezioni immutabili e sono curioso di come deserializzare usando Gson. Come nessuno ha risposto e ho trovato la soluzione da solo, sto semplificando la domanda e presentando la mia risposta.Deserializing ImmutableList using Gson

ho avuto due problemi:

  • Come scrivere un singolo Deserializer di lavoro per tutti ImmutableList<XXX>?
  • Come registrarlo per tutti ImmutableList<XXX>?

risposta

10

Update: C'è https://github.com/acebaggins/gson-serializers che copre molte collezioni guava:

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap

Come scrivere una sola Deserializer di lavoro per tutti ImmutableList?

L'idea è semplice, trasformare il passato Type che rappresenta un ImmutableList<T> in un Type che rappresenta List<T>, utilizzare il build-in capacità Gson s' per creare un List e convertirlo in un ImmutableList.

class MyJsonDeserializer implements JsonDeserializer<ImmutableList<?>> { 
    @Override 
    public ImmutableList<?> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { 
     final Type type2 = ParameterizedTypeImpl.make(List.class, ((ParameterizedType) type).getActualTypeArguments(), null); 
     final List<?> list = context.deserialize(json, type2); 
     return ImmutableList.copyOf(list); 
    } 
} 

ci sono più ParameterizedTypeImpl classi in librerie Java che uso, ma nessuno di loro destinati per l'uso pubblico. L'ho provato con sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.

Come registrarlo per tutti ImmutableList?

Quella parte è banale, il primo argomento di registrare è java.lang.reflect.Type che mi indurre in errore di utilizzare ParameterizedType, dove semplicemente utilizzando Class fa il lavoro:

final Gson gson = new GsonBuilder() 
    .registerTypeAdapter(ImmutableList.class, myJsonDeserializer) 
    .create(); 
+0

È possibile evitare l'utilizzo di ParameterizedTypeImpl? Ad esempio usando smth come: final List list = context.deserialize (json, List.class); –

+0

@Alexander Bezrodniy: ho paura, non è possibile. Puoi evitare tutto usando un 'TypeAdapter >', ma poi devi scrivere qualche altro codice boilerplate: 1.Implementa 'write' anche se l'implementazione predefinita sarebbe sufficiente, 2. Gestisci' null' in 'read'. È tutto roba di basso livello. – maaartinus

+0

Credo che ora capisco la tua domanda. Non puoi lasciare fuori i generici; senza di essi il contenuto della lista non può essere deserializzato correttamente. – maaartinus

2

@maaartinus già coperti alla seconda domanda, così ho 'll inviare una soluzione complementare Guava-based per la prima domanda che non richiede ParametrizedTypeImpl

public final class ImmutableListDeserializer implements JsonDeserializer<ImmutableList<?>> { 
    @Override 
    public ImmutableList<?> deserialize(final JsonElement json, final Type type, 
             final JsonDeserializationContext context) 
     throws JsonParseException { 
    final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); 
    final Type parameterizedType = listOf(typeArguments[0]).getType(); 
    final List<?> list = context.deserialize(json, parameterizedType); 
    return ImmutableList.copyOf(list); 
    } 

    private static <E> TypeToken<List<E>> listOf(final Type arg) { 
    return new TypeToken<List<E>>() {} 
     .where(new TypeParameter<E>() {}, (TypeToken<E>) TypeToken.of(arg)); 
    } 
} 
7

un altro imp lementation senza ParameterizedTypeImpl