Ошибка десериализации XML с использованием Джексона для сгенерированного выбора из XSD - PullRequest
0 голосов
/ 10 июня 2018

В настоящее время я пытаюсь десериализовать входящий XML для объектов, сгенерированных из XSD.К сожалению, кажется, что есть проблема при попытке десериализации сгенерированного элемента выбора.Я перепробовал довольно много вещей, и я только что реализовал очень простой пример, который можно увидеть здесь .Каждый раз я получаю одно и то же исключение.Реализация выглядит следующим образом:

public static void main(final String[] args) throws IOException {
    final String xml =
            "<Foo>    \n" +
            "    <A> 1 </A>\n" +
            "    <B> 2.5 </B>\n" +
            "</Foo>";

    final XmlMapper xmlMapper = new XmlMapper();
    final Foo foo = xmlMapper.readValue(xml, Foo.class);
}

public static class Foo {

    @XmlElementRefs({
            @XmlElementRef(name = "A", type = Integer.class),
            @XmlElementRef(name = "B", type = Float.class)
    })
    public List items;
}

В моем приложении вместо явных типов каждому элементу присваивается базовый тип JAXBElement.Исключение, которое я получаю:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "A" (class x.y.z.Application$Foo), not marked as ignorable (one known property: "items"])
 at [Source: (StringReader); line: 2, column: 15] (through reference chain: x.y.z.Application$Foo["A"])

Кажется, что он просто ищет поле с заданным именем, пытаясь установить значение, которого, конечно, не существует.

IЗдесь встречались сопоставимые вопросы, в которых указывались ответы, что вы должны добавить конфигурацию, чтобы игнорировать неизвестное, а это не то, что я хочу.Я ожидаю, что список будет содержать два элемента в конце, а именно два числа.

Я также видел расширение, называемое Simplify, чтобы сгенерировать поле списка для каждого элемента выбора.В моем случае я бы предпочел, чтобы все было добавлено в единый список.

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Для простой десериализации вы можете использовать метод setter для указания XmlMapper:

public class Foo {

    public List items;

    public Foo() {
        items = new ArrayList();
    }

    @JacksonXmlProperty(localName = "A")
    public void setA(Integer a) {
        items.add(a);
    }

    @JacksonXmlProperty(localName = "B")
    public void setB(Double b) {
        items.add(b);
    }
}

Вызов

final XmlMapper xmlMapper = new XmlMapper();
final Foo foo = xmlMapper.readValue(xml, Foo.class);

даст:

enter image description here

0 голосов
/ 13 июня 2018

Javadoc для @XmlElements, с которым вы связаны, основан на JAXB.Например, синтаксический анализ (unmarshalling) и сериализация (marshalling) этого XML с использованием JAXB напрямую:

public static void main(final String[] args)
        throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class);

    String xml = 
            "<Foo>    \n" + 
            "    <A> 1 </A>\n" +
            "    <B> 2.5 </B>\n" +
            "</Foo>";

    StringReader sr = new StringReader(xml);
    Foo foo = (Foo) jaxbContext.createUnmarshaller().unmarshal(sr);
    System.out.println(foo.items);

    StringWriter sw = new StringWriter();
    jaxbContext.createMarshaller().marshal(foo, sw);
    System.out.println(sw);
}

@XmlRootElement(name = "Foo")
public static class Foo {

    @XmlElements({ 
        @XmlElement(name = "A", type = Integer.class),
        @XmlElement(name = "B", type = Float.class) 
    })
    public List items;
}

Это приводит к выводу:

[1, 2.5]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Foo><A>1</A><B>2.5</B></Foo>

Есть несколько твиков из примера в приведенном выше вопросе.:

  • @XmlRootElement необходим для разрешения запуска <Foo> элемента
  • . Для базовых Integer и * 1018 он должен быть @XmlElement(s) вместо @XmlElementRef(s)* types

Вы правы, что Джексон также должен уметь работать с этими аннотациями.Чтобы сделать это, вам также нужно включить этот модуль: xmlMapper.registerModule(new JaxbAnnotationModule())

Однако это не слишком хорошо объединяет вещи для этого примера.Например, попробуйте снова пойти в обе стороны:

public static void main(final String[] args)
        throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.registerModule(new JaxbAnnotationModule());

    Foo foo = new Foo();
    foo.items = Arrays.asList(1, 2.5f);

    String xml = xmlMapper.writeValueAsString(foo);
    System.out.println(xml);

    xml = 
            "<Foo>    \n" + 
            "    <A> 1 </A>\n" +
            "    <B> 2.5 </B>\n" + 
            "</Foo>";

    foo = xmlMapper.readValue(xml, Foo.class);
}

public static class Foo {

    @JacksonXmlElementWrapper(useWrapping = false)
    @XmlElements({ 
        @XmlElement(name = "A", type = Integer.class),
        @XmlElement(name = "B", type = Float.class) 
    })
    public List items;
}

... вернул это ...

<Foo><items>1</items><items><B>2.5</B></items></Foo>

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "A" (class so.xmllist.XmlElementsTestBasic$Foo), not marked as ignorable (one known property: "items"])
 at [Source: (StringReader); line: 2, column: 15] (through reference chain: so.xmllist.XmlElementsTestBasic$Foo["A"])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...