Deserializing ImmutableList с использованием Gson
Я использую довольно много неизменных коллекций, и мне любопытно, как их десериализовать с помощью Gson. Поскольку никто не ответил, и я нашел решение самостоятельно, я упрощаю вопрос и представляю свой собственный ответ.
У меня было две проблемы:
- Как написать одиночный
Deserializer
для всех ImmutableList<XXX>
?
- Как зарегистрировать его для всех
ImmutableList<XXX>
?
Ответы
Ответ 1
Обновление: там https://github.com/acebaggins/gson-serializers, который охватывает множество коллекций guava:
-
ImmutableList
-
ImmutableSet
-
ImmutableSortedSet
-
ImmutableMap
-
ImmutableSortedMap
Как написать одиночный Deserializer, работающий для всех ImmutableList?
Идея проста, преобразуйте прошедший Type
, представляющий ImmutableList<T>
в Type
, представляющий List<T>
, используйте встроенную возможность Gson
для создания 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);
}
}
В Java-библиотеках я использую несколько классов ParameterizedTypeImpl
, но ни один из них не предназначен для общего использования. Я тестировал его с помощью sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
.
Как зарегистрировать его для всех ImmutableList?
Эта часть тривиальна, первый аргумент для регистрации - это java.lang.reflect.Type
, который вводит меня в заблуждение при использовании ParameterizedType
, где просто используя Class
выполняет задание:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(ImmutableList.class, myJsonDeserializer)
.create();
Ответ 2
Еще одна реализация без параметра 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);
}
Ответ 3
@maaartinus уже рассмотрел второй вопрос, поэтому я поставлю дополнительное решение на основе Guava для первого вопроса, который не требует 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));
}
}