2011-10-09 13 views
11

Używam kilku niezmiennych kolekcji i jestem ciekawy, jak deserializować je za pomocą Gson. Ponieważ nikt nie odpowiedział i sam znalazłem rozwiązanie, upraszczam pytanie i przedstawiam własną odpowiedź.Deserializowanie ImmutableList za pomocą Gsona

miałem dwa problemy:

  • Jak napisać pojedynczy Deserializer pracy dla wszystkich ImmutableList<XXX>?
  • Jak zarejestrować go dla wszystkich ImmutableList<XXX>?

Odpowiedz

10

Aktualizacja: Jest https://github.com/acebaggins/gson-serializers która obejmuje wiele kolekcji guava:

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap

Jak napisać pojedynczy Deserializator pracy dla wszystkich ImmutableList?

Pomysł jest prosty, przekształcić przekazany Type reprezentujący ImmutableList<T> w Type reprezentujących List<T> użyj wbudowany zdolności Gson „s stworzyć List i przekonwertować go do 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); 
    } 
} 

Istnieje wiele ParameterizedTypeImpl zajęcia w bibliotekach Java używam, ale żaden z nich przeznaczone są do użytku publicznego. Przetestowałem to pod numerem sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.

Jak zarejestrować go dla wszystkich ImmutableList?

Ta część jest trywialne, pierwszy argument do rejestracji jest java.lang.reflect.Type które wprowadzają w błąd mnie do korzystania ParameterizedType, gdzie po prostu za pomocą Class ma zadanie:

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

możemy uniknąć korzystania z ParameterizedTypeImpl? Na przykład za pomocą smth like: final Lista list = context.deserialize (json, List.class); –

+0

@Alexander Bezrodniy: Obawiam się, że to niemożliwe. Możesz tego uniknąć, używając 'TypeAdapter >', ale musisz napisać inny kod: 1.Wdróż "write", nawet jeśli wystarczałaby domyślna implementacja, 2. Rozdaj z 'null' w' read'. To wszystko trochę na niskim poziomie. – maaartinus

+0

Chyba teraz rozumiem twoje pytanie. Nie można pominąć generycznych; bez nich zawartość listy nie może zostać prawidłowo sformatowana. – maaartinus

2

@maaartinus już pokryte na drugie pytanie, więc ja „ll dodawać komplementarnego rozwiązania guawa opartego na pierwsze pytanie, które nie wymagają 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

One więcej imp lementation bez ParameterizedTypeImpl

@Override 
public ImmutableList<?> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) throws JsonParseException { 
    @SuppressWarnings("unchecked") 
    final TypeToken<ImmutableList<?>> immutableListToken = (TypeToken<ImmutableList<?>>) TypeToken.of(type); 
    final TypeToken<? super ImmutableList<?>> listToken = immutableListToken.getSupertype(List.class); 
    final List<?> list = context.deserialize(json, listToken.getType()); 
    return ImmutableList.copyOf(list); 
} 
Powiązane problemy