Java:如何反序列化一个包含null值的JSON数组

4

我有一个这样的JSON:

{
  "values": [
    [
      123456,
      789.0
    ],
    [
      123457,
      null
    ]
  ]
}

"schema"是这样的:每个值都是一个包含两个元素的数组,第一个是长整型,第二个是双精度浮点数(或null)。我想将它解析成Java对象(仅为POJO)。
我尝试了Jackson,但它有一个已知的bug,防止数组中的null起作用:https://github.com/FasterXML/jackson-databind/issues/403 我还尝试了Gson,但它显然无法处理将数组转换为Java对象的想法(而不是Java数组):
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 3 column 6

这里有一个完整的测试类,演示了Jackson和Gson在这个简单任务中的无法工作:

import java.util.List;

import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.map.ObjectMapper;

import com.google.gson.Gson;

public class JsonTest {

    private static final String TEST_JSON = 
                    "{\n" +
                    "  \"values\": [\n" +
                    "    [\n" +
                    "      123456,\n" +
                    "      789.0\n" +
                    "    ],\n" +
                    "    [\n" +
                    "      123457,\n" +
                    "      null\n" +
                    "    ]\n" +
                    "  ]\n" +
                    "}\n";

    public static class MyPojo1 {
        public List<TimestampAndValue> values;

        public static class TimestampAndValue {
            public long timestamp;
            public Double value;
            @JsonCreator
            public TimestampAndValue(List<Number> nums) {
                if(nums == null || nums.size() < 2) {
                    throw new IllegalArgumentException(String.format("Expected at least two numbers (timestamp & value), instead got: %s", nums));
                }
                this.timestamp = nums.get(0).longValue();
                this.value = nums.get(1).doubleValue();
            }
        }
    }

    public static class MyPojo2 {
        public List<TimestampAndValue> values;

        public static class TimestampAndValue {
            public long timestamp;
            public Double value;
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println(new ObjectMapper().readValue(TEST_JSON, MyPojo1.class));
        } catch(Throwable t) {
            t.printStackTrace();
        }
        try {
            System.out.println(new Gson().fromJson(TEST_JSON, MyPojo2.class));
        } catch(Throwable t) {
            t.printStackTrace();
        }
    }

}

问题:如何将这个JSON解析成Java对象?我想使用org.json提供的原始材料来构建自己的简单解析器,因为现有的库并不是那么方便。


我认为你应该从TEST_JSON中删除\n,这将提高可读性并不会影响行为。 - Dmitry Ginzburg
实际上,这会降低可读性,因为库的失败消息将无法指示错误发生在哪一行。 :) - syenmesh
3个回答

4

下面是一个自包含、简化的示例,展示如何使用Jackson实现:

// my pojo
public class Main {
    // my property - it's a 2-dim array (might work with a List of Lists as well)
    @JsonProperty(value = "values")
    Double[][] values;
    public static void main(String[] args) throws Exception {
        ObjectMapper om = new ObjectMapper();
        String json = "{\"values\":[[123456,789.0],[123457,null]]}";
        Main m = om.readValue(json, Main.class);
        // prints the de-serialized json
        System.out.println(Arrays.deepToString(m.values));
    }
}

输出

[[123456.0, 789.0], [123457.0, null]]

注意事项

  • 我使用的是Doubles而不是基本数据类型,因此它们是可空的,并且在使用ObjectMapper时无需添加任何附加设置。
  • 您似乎正在使用List<Number>,但您在JSON中看到的更像是一个二维数组(或List中的Lists)。
  • 我使用的是最新版本的Jackson库(即Maven中的版本)。目前最新稳定版本为2.3.2,但是Maven搜索将返回最新版本2.4.1.3-请参见Alexey的评论。
  • 有关详细信息,请参见Jackson主页

1
请注意,最新的Jackson databind版本是2.4.1.3。http://search.maven.org/#search%7Cga%7C1%7Cjackson-core - Alexey Gavrilov
1
@AlexeyGavrilov 谢谢,我可能把它和他们网站上宣传的最新稳定版混淆了。 - Mena

0

看起来我在使用数据类型和库方面做了太多的尝试,而这两个东西并不真正支持它。

在这种情况下,输入的JSON已知具有常规结构:“values”是一个包含子数组的数组,每个子数组始终为大小2,第一个项目是长整型,第二个是双精度浮点数(或null)。因此,我希望可以直接将其转换为适当的POJO。我的想法是,如果某个数组的元素数量不等于2,或者元素不是长整型和(可空)双精度浮点数,则会出现解析错误;否则,它会自动转换为POJO。

相反,我采用了手动解析数组的方式,使用标准的JSON Java library。我正在手动进行有效性检查,将值累积到列表中,并返回该列表。作为奖励,我的POJO中的字段现在可以轻松地成为public final,这很好。你也可以使用Jackson或Gson将JSON转换为基本类型(请参见其他答案),但那样你仍然需要手动检查这些基本类型,这似乎有点违背使用高级库的初衷。

我仍然认为使用库来进行此转换会更好,但不确定是否有支持它的库。

0
如果您想要使用GSON,则需要进行以下更改: MyPojo2类
public class MyPojo2 
{
    public List<List<Double>> values;

    public List<List<Double>> getValues() {
        return values;
    }

    public void setValues(List<List<Double>> values) {
        this.values = values;
    }
}  

您的 JSON 包含列表嵌套列表,您需要为类对象 values 使用相同的数据类型。

测试类

public static void main (String[] args)
    {
        try 
        {
            String json = "{\"values\":[[123456,789],[123457,null]]}";
            MyPojo2 obj = null;

            Gson gson = new Gson();
            obj = gson.fromJson(json, MyPojo2.class);
            System.out.println(obj);
            System.out.println(gson.toJson(obj));
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

样例输出:

MyPojo2@b09697
{"values":[[123456.0,789.0],[123457.0,null]]}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接