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

Простое использование TypeAdapterFactory

AFAIK самая гибкая настройка gson возможна через TypeAdapterFactory, однако она может оказаться излишне сложной. Это заставляет меня писать для каждого обработанного класса как read, так и write, хотя иногда нужен только один метод. Более того, иногда JsonSerializer и/или JsonDeserializer было гораздо проще писать, например. как здесь. Это приводит меня к этим вопросам:

  • Можно ли написать TypeAdapter, который просто делегирует один из своих методов (например, запись ImmutableList в запись List)?
  • Можно ли как-то использовать JsonSerializer и/или JsonDeserializer вместе с TypeAdapterFactory? В качестве альтернативы, существует ли для них factory?
4b9b3361

Ответ 1

Можно создать TypeAdapter, который делегирует один из своих методов. Этот вариант использования является важной частью API, и для этой цели существует метод getDelegateAdapter(). Передайте this в качестве первого аргумента getDelegateAdapter, который вернет адаптер, который имеет приоритет после текущего factory.

TypeAdapterFactory immutableListFactory = new TypeAdapterFactory() {
  @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    if (!(type.getType() instanceof ParameterizedType)
        || !type.getRawType().equals(ImmutableList.class)) {
      return null;
    }

    ParameterizedType parameterizedType = (ParameterizedType) type.getType();
    TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
    TypeAdapter<?> elementAdapter = gson.getAdapter(
        TypeToken.get(parameterizedType.getActualTypeArguments()[0]));
    return new ImmutableListAdapter(delegate, elementAdapter);
  }

  class ImmutableListAdapter<E> extends TypeAdapter<ImmutableList<E>> {
    private TypeAdapter<List<E>> delegate;
    private TypeAdapter<E> element;

    ImmutableListAdapter(TypeAdapter<List<E>> delegate, TypeAdapter<E> element) {
      this.delegate = delegate;
      this.element = element;
    }

    @Override public void write(JsonWriter out, ImmutableList<E> value) throws IOException {
      delegate.write(out, value);
    }

    @Override public ImmutableList<E> read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }
      ImmutableList.Builder<E> builder = ImmutableList.builder();
      in.beginArray();
      while (in.hasNext()) {
        builder.add(element.read(in));
      }
      in.endArray();
      return builder.build();
    }
  }
};

Вы можете смешивать и сопоставлять JsonSerializer/JsonDeserializer с TypeAdapterFactory, но не напрямую. Самый простой способ - перезвонить в Gson для сериализации дочерних значений в вашем классе. В этом примере мы изменили бы внутренний цикл на это:

      while (in.hasNext()) {
        builder.add(gson.<E>fromJson(in, elementType));
      }

Основное различие между JsonSerializer/JsonDeserializer и TypeAdapter заключается в том, сколько этапов требуется для перехода от JSON к вашей объектной модели. При JsonSerializer/JsonDeserializer объекты сначала преобразуются в модель Gson DOM (JsonElement и т.д.), А затем преобразуются в вашу объектную модель. С TypeAdapter промежуточный шаг пропускается.

Это делает код адаптера типа немного сложнее читать и писать, поэтому вы должны предпочесть его только для оптимизированного кода.