使用Jackson反序列化XML以从XSD生成选择时出错

时间:2018-06-10 19:02:33

标签: java xml serialization xsd jackson

我目前正在尝试将传入的XML反序列化为从XSD生成的对象。遗憾的是,在尝试反序列化生成的选择元素时似乎存在问题。我已经尝试了很多东西,我甚至只是实现了可以看到here的基本示例。每次我得到同样的例外。实施如下:

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"])

看起来他只是在寻找一个具有给定名称的字段,试图将值设置为此,这当然不存在。

我在这里看到了类似的问题,其中答案声明你应该添加一个配置来忽略未知,这不是我想要的。我希望列表最后包含两个元素,即两个数字。

我还看到了一个名为Simplify的扩展,以便为每个选择元素生成一个列表字段。在我的用例中,我实际上更愿意将所有内容添加到单个列表中。

2 个答案:

答案 0 :(得分:1)

您链接到的@XmlElements的Javadoc基于JAXB。例如。使用JAXB直接解析(解组)和序列化(编组)XML:

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>
  • 对于基本@XmlElement(s)@XmlElementRef(s)类型
  • ,它必须是Integer而不是Float

你是对的,杰克逊也应该能够使用那些注释。为此,您还需要启用该模块: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"])

答案 1 :(得分:1)

对于反序列化,您可以使用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