为了账号安全,请及时绑定邮箱和手机立即绑定

Gson 使用 TypeAdapter 或 Json Deserializer 将数据从错误列表

Gson 使用 TypeAdapter 或 Json Deserializer 将数据从错误列表

holdtom 2022-07-27 20:51:13
让我们从例子开始:如果数据正确,应该是(Beijing cities为空){   "code":200,   "msg":"success",   "data":[      {         "id":1,         "name":"Beijing",         "cities":[]      },      {         "id":2,         "name":"Guangdong",         "cities":[            {               "id":1,               "name":"Guangzhou"            }         ]      }   ]}现在我得到了错误的数据。(Beijing cities为空){   "code":200,   "msg":"success",   "data":[      {         "id":1,         "name":"Beijing",         "cities":null      },      {         "id":2,         "name":"Guangdong",         "cities":[            {               "id":1,               "name":"Guangzhou"            }         ]      }   ]}我正在使用Retrofit2 ResponseBodyConverter实体类:public class Result<T> {    private int code;    private String msg;    private T data;    // getters, setters}public class Province {    private int id;    private String name;    private List<City> cities;}public class City {    private int id;    private String name;}
查看完整描述

1 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

我找到了CollectionTypeAdapterFactory源Gson代码。我尝试修改它,它已经过测试并且很有用。


public class CollectionTypeAdapterFactory implements TypeAdapterFactory {

    private final ConstructorConstructor constructorConstructor;


    public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {

        this.constructorConstructor = constructorConstructor;

    }


    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {

        Type type = typeToken.getType();


        Class<? super T> rawType = typeToken.getRawType();

        if (!Collection.class.isAssignableFrom(rawType)) {

            return null;

        }


        Type elementType = $Gson$Types.getCollectionElementType(type, rawType);

        TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));

        ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);


        @SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter

                TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);

        return result;

    }


    private static final class Adapter<E> extends TypeAdapter<Collection<E>> {

        private final TypeAdapter<E> elementTypeAdapter;

        private final ObjectConstructor<? extends Collection<E>> constructor;


        public Adapter(Gson context, Type elementType,

                       TypeAdapter<E> elementTypeAdapter,

                       ObjectConstructor<? extends Collection<E>> constructor) {

            this.elementTypeAdapter =

                    new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);

            this.constructor = constructor;

        }


        public Collection<E> read(JsonReader in) throws IOException {

            if (in.peek() == JsonToken.NULL) {

                in.nextNull();

                //In the source code is return null, I changed to return an empty collection

                return constructor.construct();

            }


            Collection<E> collection = constructor.construct();

            in.beginArray();

            while (in.hasNext()) {

                E instance = elementTypeAdapter.read(in);

                collection.add(instance);

            }

            in.endArray();

            return collection;

        }


        public void write(JsonWriter out, Collection<E> collection) throws IOException {

            if (collection == null) {

                out.nullValue();

                return;

            }


            out.beginArray();

            for (E element : collection) {

                elementTypeAdapter.write(out, element);

            }

            out.endArray();

        }

    }

}

在源代码中TypeAdapterRuntimeTypeWrapper是受保护的,我们必须进行复制。


  public class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {

      private final Gson context;

      private final TypeAdapter<T> delegate;

      private final Type type;


      TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {

          this.context = context;

          this.delegate = delegate;

          this.type = type;

      }


      @Override

      public T read(JsonReader in) throws IOException {

          return delegate.read(in);

      }


      @SuppressWarnings({"rawtypes", "unchecked"})

      @Override

      public void write(JsonWriter out, T value) throws IOException {

          TypeAdapter chosen = delegate;

          Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);

          if (runtimeType != type) {

              TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));

              if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {

                  // The user registered a type adapter for the runtime type, so we will use that

                  chosen = runtimeTypeAdapter;

              } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {

                  // The user registered a type adapter for Base class, so we prefer it over the

                  // reflective type adapter for the runtime type

                  chosen = delegate;

              } else {

                  // Use the type adapter for runtime type

                  chosen = runtimeTypeAdapter;

              }

          }

          chosen.write(out, value);

      }


      private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {

          if (value != null

                  && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {

              type = value.getClass();

          }

          return type;

      }

  }

如何使用


Gson gson = new GsonBuilder().serializeNulls()

           .registerTypeAdapterFactory(

             new CollectionTypeAdapterFactory(new ConstructorConstructor(new HashMap<>()))

             )

           .create();


Result<List<Province>> result = gson.fromJson(jsonStr, new TypeToken<Result<List<Province>>>() {}.getType());

印刷:


Result{code=200, msg='success', data=[Province{id=1, name='Beijing', cities=[]}, Province{id=2, name='Guangdong', cities=[City{id=1, name='Guangzhou'}]}]}



查看完整回答
反对 回复 2022-07-27
  • 1 回答
  • 0 关注
  • 199 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信