有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用Jackson将JSON反序列化为异构元素列表

在我的JSON中,我有一个包含以下内容的元素:

{
    ...
    "locations": [
        [
            {
                "location_type": "permanent",
                "position": "at",
                "accuracy": "exact"
            },
            "and",
            {
                "location_type": "permanent",
                "position": "in",
                "accuracy": "exact"
            }
        ],
        "or",
        {
            "location_type": "temporary",
            "position": "at",
            "accuracy": "exact"
        }
    ],
    ...
}

如图所示,locations的元素可以是:

  • 地点
  • 逻辑运算符
  • 位置列表(允许复杂位置)

我得到的是“无法从START\u数组令牌中反序列化com.example.processor.transformation.json.Location的实例”

如何使用Jackson将其转换为数据结构

到目前为止,我尝试的是:

  1. 提供Location(String logicalOperator)构造函数有助于平面列表的情况。(我基本上将运算符转换为一个特殊值^{
  2. 添加Location(List<Location> subLocations)Location(Location[] subLocations)构造函数对这种情况没有帮助

注意:我无法控制JSON格式,因此无法以更友好的方式对其进行编码


共 (1) 个答案

  1. # 1 楼答案

    你需要一个自定义的反序列化程序。你不能只添加一个构造函数

    下面是一个包含类Foo的自包含示例,它可以由自己的属性"foo" : "someString"或一些逻辑运算符"and""or"等表示为String文字,旨在表示Foo实例,其foo属性将是该文字的值

    这可能完全适合您的情况,也可能不适合您的情况,但您可以进行调整

    换句话说:

    • {"foo": "a"}>new Foo("a")
    • "or">new Foo("or")

    示例

    // given...
    
    @JsonDeserialize(using=MyDeserializer.class)
    class Foo {
        String foo;
        public void setFoo(String s) {
            foo = s;
        }
        public String getFoo() {
            return foo;
        }
        public Foo(String s) {
            setFoo(s);
        }
    }
    

    //和自定义反序列化程序

    class MyDeserializer extends JsonDeserializer<Foo> {
    
        @Override
        public Foo deserialize(JsonParser jp, DeserializationContext ct)
                throws IOException, JsonProcessingException {
            ObjectCodec oc = jp.getCodec();
            JsonNode node = oc.readTree(jp);
            // this JSON object has a "foo" property, de-serialize 
            // injecting its value in Foo's constructor
            if (node.has("foo")) {
                return new Foo(node.get("foo").asText());
            }
            // other case, assuming literal (e.g. "and", "or", etc.)
            // inject actual node as String value into Foo's constructor
            else {
                return new Foo(node.asText());
            }
        }
    
    }
    
    // here's a quick example
    
    String json = "[{\"foo\": \"a\"}, \"or\", {\"foo\": \"b\"}]";
    ObjectMapper om = new ObjectMapper();
    List<Foo> list = om.readValue(json, new TypeReference<List<Foo>>(){});
    list.forEach(f -> System.out.println(f.foo));
    

    输出

    a
    or
    b
    

    为清晰起见,请注意

    这是一个非常简单的例子。 在你的例子中,你可能会想要一个多态的Locationpojo集合与LogicalOperatorpojo(或类似的东西)混合,共享一个共同的标记接口。 然后,您可以根据JSON节点是以内容为特征(即位置)还是JSON节点其内容(例如逻辑运算符)来决定反序列化哪个对象