Simpler use of TypeAdapterFactory

烈酒焚心 提交于 2019-11-30 11:45:58

It is possible to create a TypeAdapter that delegates one of its methods. This use case is an important part of the API, and there's a getDelegateAdapter() method for just this purpose. Pass this as the first argument to getDelegateAdapter which will return the adapter that takes precedence after the current 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();
    }
  }
};

You can mix and match JsonSerializer/JsonDeserializer with TypeAdapterFactory, but not directly. The simplest way is to call back into Gson to serialize child values in your class. In this example we'd change the inner loop to this:

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

The main difference between JsonSerializer/JsonDeserializer and TypeAdapter is how many stages it takes to go from JSON to your object model. With JsonSerializer/JsonDeserializer objects are first converted to Gson's DOM model (JsonElement etc.) and then converted into your object model. With TypeAdapter, the intermediate step is skipped.

This makes the type adapter code a little trickier to read and write, so you should prefer it only for optimized code.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!