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

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

因此,它不应该作为 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/

相关文章:

java - 带有要反序列化的整数数组的 POJO

java - 如何在 Bazel 中为 Android 项目添加 Maven 依赖项(例如 Volley、Gson)?

android - 在路径 : DexPathList on Android Library 上找不到类

java - 如何使加载的jar使用自身资源而不是加载器?

java - 从 CMD 运行 Selenium IDE 测试用例

java - 如何将数组从 TMDB 保存到 SQLite

java - 如何从 CSV 文件中获取特定数据

java - Retrofit:使用 GSON 将 JSON 解析为多个 Java 对象

android - Retrofit2标量转换器在gson转换器android之前不转换

retrofit - 无法为 io.reactivex.Observable 创建调用适配器