我从服务器返回了一个返回结果:
[{
"id":"1",
"objectOne": {
"name":"jim"
}
}, {
"id":"1",
"objectOne": [{
"name": "jim1"
}, {
"name": "jim2"
}
}, {
"id":"1",
"objectOne": null
}]
也就是说,一个值可以是对象、对象数组或 null。
我将 Gson 转换器与 Retrofit 结合使用,并使用此 TypeAdapterFactory 强制将单个对象读取为数组:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapterFactory(new ObjectToArrayFactory());
Gson gson = gsonBuilder.create();
工厂:
private class ObjectToArrayAdapter<T> extends TypeAdapter<List<T>> {
Gson gson;
private Class<T> adapterclass;
public ObjectToArrayAdapter(Gson gson, Class<T> adapterclass) {
this.gson = gson;
this.adapterclass = adapterclass;
}
@Override
public void write(JsonWriter out, List<T> value) throws IOException {}
public List<T> read(JsonReader reader) throws IOException {
List<T> list = new ArrayList<T>();
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
// If it's meant to be an array and instead it's a single object, add it to a newly created list.
parseObject(list, reader, gson);
} else if (reader.peek() == JsonToken.BEGIN_ARRAY) {
// Otherwise, if it is actually a list, manually parse each item and add it to the list
parseArray(list, reader, gson);
} else if(reader.peek() == JsonToken.NULL) {
// However if the server gives a null object, just return null.
return null;
}
return list;
}
private void parseArray(List<T> list, JsonReader reader, Gson gson) throws IOException {
reader.beginArray();
while (reader.hasNext()) {
parseObject(list, reader, gson);
}
reader.endArray();
}
private void parseObject(List<T> list, JsonReader reader, Gson gson) throws IOException {
T inning = gson.fromJson(reader, adapterclass);
list.add(inning);
}
}
我的问题是,当我要求 Retrofit 将值解析为数组时:
private List<PaymentsOption> objectOne;
当 Gson 解析器到达如下所示的 json 部分时,它似乎感到困惑:
"objectOne": null
我已经通过解析调试并记录了我的方式,看起来它遵循了这个代码路径(为了简洁起见,我已经解析出了实际的代码):
if(reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while(reader.hasNext()) { // public void parseTag()
if(reader.peek() == JsonToken.BEGIN_OBJECT) {
T inning = gson.fromJson(reader, adapterclass); <-- Crashes here
}
}
reader.endArray();
}
因此,它不应该作为 beginArray 进行“偷看”,因为它是“null”。它也不应该允许 reader.beginArray() 因为它仍然是“null”。它应该再次查看并看到 beginObject。它允许在 gson.fromJson 内部使用 reader.beginObject(),但在 reader.readName() 上失败,因为它实际上读取的是“null”。异常情况如下:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a name but was NULL at line 24 column 39 path $[1].objectOne
10-27 12:05:20.452 E/Exception: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200)
10-27 12:05:20.452 E/Exception: at com.google.gson.Gson.fromJson(Gson.java:810)
10-27 12:05:20.452 E/Exception: at uk.co.utils.network.ObjectToArrayFactory$ObjectToArrayAdapter.parseTag(ObjectToArrayFactory.java:70)
我不明白为什么 reader.peek() 首先显示一个 beginArray,允许 reader.beginArray(),然后将 reader.peek() 显示为 beginObject() 以及为什么它允许 reader.beginObject ()。据我了解,它应该显示 reader.peek() == Json.Token.NULL ...?
最佳答案
您需要编写一个 TypeAdapter
并在构建 gson 对象时注册它。在适配器的读取方法中,您可以检查给定参数是否为空或为空,并采取相应的操作。您的读取方法将如下所示:
public Number read(JsonReader in) throws IOException{
if(in.peek() == JsonToken.NULL) in.nextNull();
try{
//read value and take suitable action
}catch(Exception e){}
}
但是您需要为需要特殊处理的每种不同数据类型编写一个 typeAdapter。
关于java - Gson 将 "null"对象解析为数组/对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33365360/