Десериализация из xml двух пересекающихся списков
Пытаюсь прочитать следующую структуру xml:
<root>
<foo name="AAA" />
<bar name="BBB" />
<foo name="CCC" />
<bar name="DDD" />
</root>
Классы java:
public class Foo { // public class Bar {...
@JacksonXmlProperty(isAttribute = true)
private String name;
// getters + setters + constructor
}
public class Root {
@JacksonXmlProperty(localName = "foo")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Foo> foos;
@JacksonXmlProperty(localName = "bar")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Bar> bars;
// getters + setters + constructor
}
Читаю xml следующим образом:
System.out.println(new XmlMapper().readValue(xml, Root.class));
Но в результате почему-то пропадают объекты "AAA" и "BBB":
Root(foos=[Foo(name=CCC)], bars=[Bar(name=DDD)])
Причём, если упорядочить элементы в исходном xml: сначала foo, потом bar, - тогда все объекты читаются нормально:
Root(foos=[Foo(name=AAA), Foo(name=CCC)], bars=[Bar(name=BBB), Bar(name=DDD)])
Использую jackson-dataformat-xml 2.11.2, последнюю на текущий момент.
Что здесь происходит? Как это исправить?
Свободный перевод вопроса: «Jackson XML deserialization skips field when using multiple useWrapping = false» от участника @michael.
Ответы (1 шт):
Для любого логического свойства JacksonXmlProperty можно указать метод JsonSetter или JsonGetter - это может оказаться проще, чем писать собственный Deserializer / Serializer для всего класса. Ещё есть аннотация JsonAnySetter, которую можно использовать как резервный вариант для чего-то, что не указано в вашем классе, например, можно поместить все XML-атрибуты элемента в одну карту, а не указывать свойства для каждого возможного атрибута.
В данном случае для десериализации элементов двух списков в классе Root нужно добавить кастомные сеттеры JsonSetter:
@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);
}
Root(foos=[Foo(name=AAA), Foo(name=CCC)], bars=[Bar(name=BBB), Bar(name=DDD)])
При формировании ответа использовался ответ на вопрос «Jackson XML deserialization skips field when using multiple useWrapping = false» от участника @jnorman.