Jackson XML 反序列化在使用多个 useWrapping = false 时跳过字段
Jackson XML deserialization skips field when using multiple useWrapping = false
我正在尝试反序列化以下 XML:
<root>
<foo name="AAA" />
<bar name="BBB" />
<foo name="CCC" />
</root>
我的杰克逊class是:
@Data
public class Foo {
@JacksonXmlProperty(isAttribute = true)
private String name;
}
酒吧是相同的,只是 class 名称不同。 (在实际代码中它们是不同的,这只是一个例子)。
根class是
@Data
public class Root {
@JacksonXmlProperty(localName = "foo")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Foo> foos;
@JacksonXmlProperty(localName = "bar")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Bar> bars;
}
当我尝试反序列化 XML 时,使用此代码
System.out.println(new XmlMapper().readValue(theXml, Root.class));
结果是这样的(注意缺少“AAA”):
Root(foos=[Foo(name=CCC)], bars=[Bar(name=BBB)])
但是,如果我移动 XML 中的字段,使两个 foo
标签彼此相邻,它会打印
Root(foos=[Foo(name=AAA), Foo(name=CCC)], bars=[Bar(name=BBB)])
我正在使用 jackson-dataformat-xml 2.11.1,这是最新的。
这是怎么回事,我该如何解决?
我必须认识到,我通常只使用 Jackson 进行 JSON 处理,但它似乎是 jackson-dataformat-xml
库的 known limitation:
Prior to 2.12 (not yet released as of May 2020), handling of repeated XML elements was problematic (it could only retain the last element read), but #403 improves handling
也许这个问题可能与您的问题有关。
作为解决方法,如果可能,您可以在处理 XML 文档之前对它们应用某种 XSLT 转换,以便将所有同名节点组合在一起,并查看结果是否是不出所料。
您也可以尝试其他反序列化替代方案,主要是 JAXB,或者直接 XML 处理。
对于任何 属性,您可以指定一个方法作为 setter 或 getter 使用 Jackson 注释(JsonSetter and JsonGetter). When you just a need a little modification to what Jackson is doing, then this seems easier that writing a custom deserializer
/ serializer
for the whole class. Jackson also has a JsonAnySetter 注释,它是用于class 中未指定的内容(我发现它有时很方便;我用它来将一种元素的所有 XML 属性放入单个 Map 而不必具有属性对于每个可能的属性)。
您可以将自定义 XML 反序列化方法添加到根目录 class。像这样:
@JsonSetter(value = "foo")
public void setFooFromXml(Foo foo) {
if (this.foos == null) {
this.foos = new ArrayList<Foo>();
}
this.foos.add(foo);
}
@JsonSetter(value = "bar")
public void setBarFromXml(Bar bar) {
if (this.bars == null) {
this.bars = new ArrayList<Bar>();
}
this.bars.add(bar);
}
像这样使用 Jackson 反序列化 XML:
try {
String input = "<root><foo name=\"AAA\" /><bar name=\"BBB\" /><foo name=\"CCC\" /></root>";
XmlMapper mapper = new XmlMapper();
Root root = mapper.readValue(input, Root.class);
System.out.println(root.getBars());
System.out.println(root.getFoos());
} catch (Exception e) {
e.printStackTrace();
}
给出这个输出(在添加一些简单的 toString() 和 getter 方法之后):
[Bar [name=BBB]]
[Foo [name=AAA], Foo [name=CCC]]
我正在尝试反序列化以下 XML:
<root>
<foo name="AAA" />
<bar name="BBB" />
<foo name="CCC" />
</root>
我的杰克逊class是:
@Data
public class Foo {
@JacksonXmlProperty(isAttribute = true)
private String name;
}
酒吧是相同的,只是 class 名称不同。 (在实际代码中它们是不同的,这只是一个例子)。
根class是
@Data
public class Root {
@JacksonXmlProperty(localName = "foo")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Foo> foos;
@JacksonXmlProperty(localName = "bar")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Bar> bars;
}
当我尝试反序列化 XML 时,使用此代码
System.out.println(new XmlMapper().readValue(theXml, Root.class));
结果是这样的(注意缺少“AAA”):
Root(foos=[Foo(name=CCC)], bars=[Bar(name=BBB)])
但是,如果我移动 XML 中的字段,使两个 foo
标签彼此相邻,它会打印
Root(foos=[Foo(name=AAA), Foo(name=CCC)], bars=[Bar(name=BBB)])
我正在使用 jackson-dataformat-xml 2.11.1,这是最新的。
这是怎么回事,我该如何解决?
我必须认识到,我通常只使用 Jackson 进行 JSON 处理,但它似乎是 jackson-dataformat-xml
库的 known limitation:
Prior to 2.12 (not yet released as of May 2020), handling of repeated XML elements was problematic (it could only retain the last element read), but #403 improves handling
也许这个问题可能与您的问题有关。
作为解决方法,如果可能,您可以在处理 XML 文档之前对它们应用某种 XSLT 转换,以便将所有同名节点组合在一起,并查看结果是否是不出所料。
您也可以尝试其他反序列化替代方案,主要是 JAXB,或者直接 XML 处理。
对于任何 属性,您可以指定一个方法作为 setter 或 getter 使用 Jackson 注释(JsonSetter and JsonGetter). When you just a need a little modification to what Jackson is doing, then this seems easier that writing a custom deserializer
/ serializer
for the whole class. Jackson also has a JsonAnySetter 注释,它是用于class 中未指定的内容(我发现它有时很方便;我用它来将一种元素的所有 XML 属性放入单个 Map 而不必具有属性对于每个可能的属性)。
您可以将自定义 XML 反序列化方法添加到根目录 class。像这样:
@JsonSetter(value = "foo")
public void setFooFromXml(Foo foo) {
if (this.foos == null) {
this.foos = new ArrayList<Foo>();
}
this.foos.add(foo);
}
@JsonSetter(value = "bar")
public void setBarFromXml(Bar bar) {
if (this.bars == null) {
this.bars = new ArrayList<Bar>();
}
this.bars.add(bar);
}
像这样使用 Jackson 反序列化 XML:
try {
String input = "<root><foo name=\"AAA\" /><bar name=\"BBB\" /><foo name=\"CCC\" /></root>";
XmlMapper mapper = new XmlMapper();
Root root = mapper.readValue(input, Root.class);
System.out.println(root.getBars());
System.out.println(root.getFoos());
} catch (Exception e) {
e.printStackTrace();
}
给出这个输出(在添加一些简单的 toString() 和 getter 方法之后):
[Bar [name=BBB]]
[Foo [name=AAA], Foo [name=CCC]]