2011-10-09 4 views
11

Я использую довольно много неизменных коллекций, и мне любопытно, как их десериализовать с помощью Gson. Поскольку никто не ответил, и я нашел решение самостоятельно, я упрощаю вопрос и представляю свой собственный ответ.Deserializing ImmutableList с использованием Gson

У меня было две проблемы:

  • Как написать один Deserializer работает для всех ImmutableList<XXX>?
  • Как зарегистрировать его для всех ImmutableList<XXX>?

ответ

10

Update: Там в https://github.com/acebaggins/gson-serializers, которая охватывает многие коллекции гуавы:

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap

Как написать один десериализатор работает для всех ImmutableList?

Идея проста, преобразование прошло Type, представляющий ImmutableList<T> в Type, представляющий List<T>, использовать встроенные возможности Gson «s создать List и преобразовать его к 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); 
    } 
} 

Есть несколько ParameterizedTypeImpl классов в Java библиотеки, которые я использую, но ни один из них не предназначен для публичного использования. Я тестировал его с помощью sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.

Как зарегистрировать его для всех ImmutableList?

Та часть тривиальна, то первый аргумент для регистрации является java.lang.reflect.Type, которые вводят в заблуждение меня к использованию ParameterizedType, где просто используя Class делает работу:

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

Можем ли мы избежать использования параметра ParameterizedTypeImpl? Например, используя smth like: final Список list = context.deserialize (json, List.class); –

+0

@ Александр Безродный: Боюсь, это невозможно. Вы можете избежать всего этого, используя 'TypeAdapter >', но тогда вам нужно написать еще один шаблонный код: 1.Реализуйте 'write', хотя реализация по умолчанию будет достаточной, 2. Поделитесь с' null' в 'read'. Все это немного низкоуровневое. – maaartinus

+0

Думаю, теперь я понимаю ваш вопрос. Вы не можете игнорировать дженерики; без них содержимое списка нельзя десериализовать должным образом. – maaartinus

2

@maaartinus уже закрывала второй вопрос, так что я выложит комплементарное решение на основе гуавы на первый вопрос, который не требует больше 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

Один импа lementation без 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); 
}