我从服务器返回可以通过以下方式返回:
[{
"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();
}
所以,它不应该是&#34;偷看&#34;作为beginArray,它是&#34; null&#34;。它也不应该允许reader.beginArray(),因为它仍然是&#34; null&#34;。它应该再次查看并看到beginObject。它允许在gson.fromJson
内部的reader.beginObject()但在reader.readName()上失败,因为它实际上正在读取&#34; null&#34;。例外情况如下:
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()以及为什么它&#39;允许reader.beginObject()。据我了解,它应该显示一个reader.peek()== Json.Token.NULL ......?
答案 0 :(得分:1)
您需要编写TypeAdapter
并在构建gson对象时注册它。在适配器的read方法中,您可以检查给定参数是否为null,或者为空并相应地采取操作。您的读取方法将如下所示:
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。