Gson解析" null"对象为数组/对象?

时间:2015-10-27 10:23:50

标签: java gson retrofit

我从服务器返回可以通过以下方式返回:

[{
    "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 ......?

1 个答案:

答案 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。