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

标签 java json data-structures jackson

在我的 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_ARRAY token 中反序列化 com.example.processor.transformation.json.Location 的实例”。

如何使用 Jackson 将其消费到数据结构中?

到目前为止我尝试过的:

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

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

最佳答案

为此,您将需要一个自定义反序列化器。您不能只添加构造函数。

这是一个类 Foo 的独立示例,它可以由其自己的属性 "foo": "someString" 或某些逻辑运算符 表示>"and""or" 等作为 String 文字,旨在表示 Foo 实例,其 foo 属性将是该文字的值。

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

换句话说:

  • {"foo": "a"} --> new Foo("a")
  • “或” --> new Foo(“或”)

示例

// 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

为了清晰起见,请注意

这是一个非常简单的示例。 在您的情况下,您可能需要一个 Location POJO 与 LogicalOperator POJO(或类似的东西)混合的多态集合,共享一个公共(public)标记接口(interface)。 然后,您可以根据 JSON 节点是否包含内容(即位置)或 JSON 节点是否是其内容(例如逻辑运算符)来决定要反序列化的对象。

关于java - 使用 Jackson 将 JSON 反序列化为异构元素列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49853558/

相关文章:

java - Java中数组寻址的时间复杂度差异

java - LinkedList 在 add() 上产生巨大的延迟

json - ModelSerializer 空字符串的字段验证

mysql - 一列或单独的列用于额外数据 - mysql

java - 这种情况下重新实例化是如何工作的?

Java打印pdf错误jhipster

java - 从某个索引开始一个字符数组

javascript - 根据对象的属性将对象数组转换为散列

algorithm - 大数据模式匹配的数据结构

algorithm - SQL 查询以更快地搜索或使用哈希表