繁体   English   中英

Gson将“空”对象解析为数组/对象?

[英]Gson parsing “null” objects as Array/Object?

我从服务器得到的回报可以是:

[{
    "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将值解析为Array时:

private List<PaymentsOption> objectOne;

当进入json的部分时,Gson解析器似乎会感到困惑:

"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();
}

因此,不应将它作为“ null”作为beginArray“偷看”。 它还不应该允许reader.beginArray(),因为它仍然是“ null”。 它应该再次窥视并看到beginObject。 它可以让内部的reader.beginObject() gson.fromJson但未能上reader.readName(),因为它实际上是读“空”。 异常如下:

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 ...?

构建gson对象时,需要编写TypeAdapter并进行注册。 在适配器的read方法中,您可以检查给定的参数是否为null或为空,或者为空,然后采取相应的措施。您的read方法将如下所示:

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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM