Джексон XMLWrapper не смог десериализовать этот xml в pojo?

#java #xml #jackson #xml-deserialization #fasterxml

Вопрос:

Рассмотрим приведенный ниже xml:

 <?xml version="1.0"?>
<Records>
    <Record>
        <Prop name="commerce">sku1</Prop>
        <Prop name="commerce">sku2</Prop>
        <Prop name="commerce">sku3</Prop>
        <Prop name="commerce">sku4</Prop>
    </Record>
    <Record>
        <Prop name="commerce">sku10</Prop>
        <Prop name="commerce">sku20</Prop>
        <Prop name="commerce">sku30</Prop>
        <Prop name="commerce">sku40</Prop>
    </Record>
</Records>
 

Теперь рассмотрим эти Pojo, которые я создал(для краткости удалив геттер и сеттеры).

 public class Records {
    private List<Record> records;
}

public class Record {
    private List<Prop> props;
}

public class Prop {
    // I want to capture name attribute
    private String name;
    // But I also want to capture what comes inside Prop element as well. This would then have values like sku1, sku2 etc
    private String text;
}
 

Теперь у меня есть код, использующий XMLWrapper, подобный этому.

 File file = ResourceUtils.getFile("classpath:sample.xml"); // the above XML is sample.xml
XmlMapper xmlMapper = XmlMapper.builder().build();
Records records = xmlMapper.readValue(file, Records.class); // this line is failing
 

Но я получаю такую ошибку

 Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Record" (class com.example.demo.model.xml.Records), not marked as ignorable (one known property: "records"])
 

Комментарии:

1. Должно @XmlElement(name = "Record") private List<Record> records; совпадать с именами элементов. Тот же принципал относится и к Prop

Ответ №1:

Даже без XML-аннотаций(по большей части) это решение, казалось, работало для меня. Публикация для потомков.

Шаг 1: Отключите перенос.

 File file = ResourceUtils.getFile("classpath:sample.xml"); 
XmlMapper xmlMapper = XmlMapper.builder().defaultUseWrapper(false).build();
Records records = xmlMapper.readValue(file, Records.class);
 

Шаг 2: Обновите pojos аннотацией JsonProperty(за исключением получения внутреннего значения с помощью @JacksonXmlText. Примечание. Для краткости удалите сеттеры и геттеры.

 public class Records {
    @JsonProperty("Record")
    private List<Record> records;
}

public class Record {
    @JsonProperty("Prop")
    private List<Prop> props;
}

public class Prop {
    @JsonProperty("name")
    private String name;

    @JacksonXmlText
    private String text;
}
 

Все вышесказанное сработало для меня.

Ответ №2:

Вы должны объединить @JacksonXmlProperty аннотацию с @JacksonXmlElementWrapper аннотацией, которая указывает элемент оболочки для использования с a Collection : в этом случае необязательное свойство useWrapping имеет значение false, чтобы явно отключить обертывание:

 public class Records {
    @JacksonXmlProperty(localName = "Record")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Record> records;
}

public class Record {
    @JacksonXmlProperty(localName = "Prop")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Prop> props;
}

public class Prop {
    //<Prop name="commerce">sku1</Prop> name is an attribute with value commerce
    @JacksonXmlProperty(localName= "name", isAttribute = true)
    private String name;
    
    //<Prop name="commerce">sku1</Prop> sku1 is the text inside the Prop tags
    @JacksonXmlText
    private String text;
}
 

Комментарии:

1. Спасибо за ваше решение. Это работает. И даже без некоторых из этих аннотаций и просто с помощью @JsonProperty я смог заставить его работать так же хорошо. Не знаю как, но это сработало. Опубликовал ответ на вопрос, заинтересует ли кого-нибудь будущее.

2. @программист, добро пожаловать. Я видел ваше решение, и оно содержит меньше кода, чем мое, глобальное отключение unwrapper с помощью defaultUseWrapper(false), безусловно, является наиболее оптимальным решением, если классы похожи на те, которые вы включили в свой вопрос. В случае, если у вас была другая модель класса, возможно, вам следовало бы аннотировать каждый класс локально, а не более глобально.