Java 使用Jackson将JSON反序列化为异构元素列表
在我的JSON中,我有一个包含以下内容的元素:Java 使用Jackson将JSON反序列化为异构元素列表,java,json,data-structures,jackson,Java,Json,Data Structures,Jackson,在我的JSON中,我有一个包含以下内容的元素: { ... "locations": [ [ { "location_type": "permanent", "position": "at", "accuracy": "exact" }, "and", {
{
...
"locations": [
[
{
"location_type": "permanent",
"position": "at",
"accuracy": "exact"
},
"and",
{
"location_type": "permanent",
"position": "in",
"accuracy": "exact"
}
],
"or",
{
"location_type": "temporary",
"position": "at",
"accuracy": "exact"
}
],
...
}
如图所示,位置的元素可以是:
- 地点
- 逻辑运算符
- 位置列表(允许复杂位置)
我得到“无法反序列化com.example.processor.transformation.json.Location的实例”
out-of-START\u数组令牌”
如何使用Jackson将其转换为数据结构?
到目前为止,我尝试的是:
提供一个位置(String logicalOperator)
构造函数有助于简化列表。(我基本上将运算符转换为特殊值位置
)
添加位置(列出子位置)
或位置(位置[]子位置)
构造函数对这种情况没有帮助
注意:我无法控制JSON格式,因此无法以更为Jackson友好的方式对其进行编码。为此,您需要一个自定义反序列化程序。你不能只添加一个构造函数
下面是一个包含类Foo
的自包含示例,它可以由自己的属性“Foo”:“someString”
,或者由某个逻辑运算符“和”
或或“
等表示为字符串
文本,用于表示Foo
实例,其Foo
属性将是该文本的值
这可能完全适合您的情况,也可能不适合您的情况,但您可以进行调整
换言之:
{“foo”:“a”}
-->新foo(“a”)
“或”
-->新食品(“或”)
示例
// 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));
为清晰起见,请注意
这是一个非常简单的例子。
在您的例子中,您可能需要一个多态的Location
pojo集合,它与LogicalOperator
pojo(或类似的东西)混合在一起,共享一个公共的标记接口。
然后,您可以根据JSON节点是以内容为特征(即位置)还是JSON节点是其内容(例如逻辑运算符)来决定反序列化哪个对象 为此,您需要一个自定义反序列化程序。您不能只添加构造函数。@Saifhmad请查看重复状态。这是一个不同的问题,有不同的解决方案。虽然这不是最终的解决方案,但我认为你为我指明了正确的方向。我试着在不同的地方应用@JsonDeserialize
,而Location
是一个接口,但这似乎并没有触发自定义反序列化程序。@AdSR“在不同的地方”是什么意思?您只需要在类/接口声明之前进行注释。如果您的位置和逻辑运算符有一个公共接口,那么可以在该接口声明之前进行注释。没关系,我尝试使用错误的Jackson包,但它与解析器不匹配(org.codehaus…
vs.com.fasterxml…
)。最后,您的解决方案和我的解决方案之间的唯一区别是,我通过node.isArray()
etc.@adsraha对节点类型进行分派。是的,org.codehaus
现在已经很旧了,这让我想起了我自己的答案:D您在自己的反序列化程序中有很多选择,最终归结为您发现哪种方法更容易处理您的全部负载。
a
or
b