gpt4 book ai didi

java - Gson使用TypeAdapter或Json Deserializer将数据从错误列表转换为空列表

转载 作者:太空宇宙 更新时间:2023-11-04 09:48:41 39 4
gpt4 key购买 nike

让我们从示例开始:

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

}

反序列化后得到的数据是这样的:
enter image description here

但是我需要的数据是这样的:
enter image description here

为了有更好的容错能力,当数据是list的时候,我想自己处理一下。
首先,我尝试使用JsonDeserializer

Gson gson = new GsonBuilder()
.serializeNulls()
.registerTypeHierarchyAdapter(List.class, new GsonListAdapter())
.create();

static class GsonListAdapter implements JsonDeserializer<List<?>> {
@Override
public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
List list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonElement element = array.get(i);
Object item = context.deserialize(element, itemType);
list.add(item);
}
return list;
} else {
return Collections.EMPTY_LIST;
}
}
}

JsonDeserializer当数据为""时有效, {} ,和[] ,但是datanull ,它不会工作。

然后我尝试使用TypeAdapter

static class GsonListAdapter extends TypeAdapter<List<?>> {

@Override
public void write(JsonWriter out, List<?> value) throws IOException {
out.value(String.valueOf(value));
}

@Override
public List<?> read(JsonReader reader) throws IOException {
if (reader.peek() != JsonToken.BEGIN_ARRAY) {
reader.skipValue();
return Collections.EMPTY_LIST;
}
return new Gson().fromJson(reader, new TypeToken<List<?>>() {}.getType());
}
}

这样一来,无论data是的,它可以正常工作。我们知道使用TypeToken<List<?>>会给我们LinkedHashMap ,所以虽然TypeAdapter可以正常工作,但不知道如何转换JsonReaderList <?> .

所以我想知道是否还有其他方法可以处理错误的列表数据?或转换JsonReaderList <?> data我想要。

最佳答案

我在Gson源码中找到了CollectionTypeAdapterFactory,尝试修改了一下,经过测试,很有用。

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是 protected ,我们必须复制一份。

  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'}]}]}

关于java - Gson使用TypeAdapter或Json Deserializer将数据从错误列表转换为空列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55085592/

39 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com