Подтвердить что ты не робот

Deserializing ImmutableList с использованием Gson

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

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

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

Ответ 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));   
  }
}