猿问

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

让我们从例子开始:


如果数据正确,应该是(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;


}


holdtom
浏览 200回答 1
1回答

绝地无双

我找到了CollectionTypeAdapterFactory源Gson代码。我尝试修改它,它已经过测试并且很有用。public class CollectionTypeAdapterFactory implements TypeAdapterFactory {&nbsp; &nbsp; private final ConstructorConstructor constructorConstructor;&nbsp; &nbsp; public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {&nbsp; &nbsp; &nbsp; &nbsp; this.constructorConstructor = constructorConstructor;&nbsp; &nbsp; }&nbsp; &nbsp; public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {&nbsp; &nbsp; &nbsp; &nbsp; Type type = typeToken.getType();&nbsp; &nbsp; &nbsp; &nbsp; Class<? super T> rawType = typeToken.getRawType();&nbsp; &nbsp; &nbsp; &nbsp; if (!Collection.class.isAssignableFrom(rawType)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; Type elementType = $Gson$Types.getCollectionElementType(type, rawType);&nbsp; &nbsp; &nbsp; &nbsp; TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));&nbsp; &nbsp; &nbsp; &nbsp; ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);&nbsp; &nbsp; &nbsp; &nbsp; @SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);&nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; }&nbsp; &nbsp; private static final class Adapter<E> extends TypeAdapter<Collection<E>> {&nbsp; &nbsp; &nbsp; &nbsp; private final TypeAdapter<E> elementTypeAdapter;&nbsp; &nbsp; &nbsp; &nbsp; private final ObjectConstructor<? extends Collection<E>> constructor;&nbsp; &nbsp; &nbsp; &nbsp; public Adapter(Gson context, Type elementType,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TypeAdapter<E> elementTypeAdapter,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ObjectConstructor<? extends Collection<E>> constructor) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.elementTypeAdapter =&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.constructor = constructor;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public Collection<E> read(JsonReader in) throws IOException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (in.peek() == JsonToken.NULL) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; in.nextNull();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //In the source code is return null, I changed to return an empty collection&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return constructor.construct();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Collection<E> collection = constructor.construct();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; in.beginArray();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (in.hasNext()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; E instance = elementTypeAdapter.read(in);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collection.add(instance);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; in.endArray();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return collection;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public void write(JsonWriter out, Collection<E> collection) throws IOException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (collection == null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.nullValue();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.beginArray();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (E element : collection) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; elementTypeAdapter.write(out, element);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.endArray();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}在源代码中TypeAdapterRuntimeTypeWrapper是受保护的,我们必须进行复制。&nbsp; public class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {&nbsp; &nbsp; &nbsp; private final Gson context;&nbsp; &nbsp; &nbsp; private final TypeAdapter<T> delegate;&nbsp; &nbsp; &nbsp; private final Type type;&nbsp; &nbsp; &nbsp; TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.context = context;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.delegate = delegate;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.type = type;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; public T read(JsonReader in) throws IOException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return delegate.read(in);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; @SuppressWarnings({"rawtypes", "unchecked"})&nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; public void write(JsonWriter out, T value) throws IOException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeAdapter chosen = delegate;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (runtimeType != type) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // The user registered a type adapter for the runtime type, so we will use that&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chosen = runtimeTypeAdapter;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // The user registered a type adapter for Base class, so we prefer it over the&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // reflective type adapter for the runtime type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chosen = delegate;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Use the type adapter for runtime type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chosen = runtimeTypeAdapter;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chosen.write(out, value);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (value != null&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type = value.getClass();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return type;&nbsp; &nbsp; &nbsp; }&nbsp; }如何使用Gson gson = new GsonBuilder().serializeNulls()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.registerTypeAdapterFactory(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new CollectionTypeAdapterFactory(new ConstructorConstructor(new HashMap<>()))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.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'}]}]}
随时随地看视频慕课网APP

相关分类

Java
我要回答