Simpler use of TypeAdapterFactory

前端 未结 1 1748
你的背包
你的背包 2021-01-02 02:52

AFAIK the most flexible gson customization is possible via TypeAdapterFactory, however it may get needlessly complicated. It forces me to write for each handled

相关标签:
1条回答
  • 2021-01-02 03:33

    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.

    0 讨论(0)
提交回复
热议问题