簡體   English   中英

如何使用@XmlElements將不同的對象放入同一列表?

[英]How to different objects into the same list using @XmlElements?

我想使用jackson xml映射器將以下xml(我必須控制並從Web服務獲取)映射到Java bean:

<foo>
    <first><val>some</val></first>
    <first><val>somemore</val></first>
    <second><testval>test</testval></second>
</foo>

我提供的架構是:

<xs:schema>
    <xs:include schemaLocation="firstType.xsd"/>
    <xs:include schemaLocation="secondType.xsd"/>
    <xs:element name="foo">
        <xs:complexType>
            <xs:sequence maxOccurs="unbounded">
                <xs:element ref="first" minOccurs="0"/>
                <xs:element ref="second" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

使用xsdtojava ,將生成以下bean:

@XmlRootElement(name = "foo")
@XmlAccessorType(XmlAccessType.FIELD)
public class XmlTest {
    @XmlElements({
        @XmlElement(name = "first", type = FirstType.class),
        @XmlElement(name = "second", type = SecondType.class)
    })
    @JsonSubTypes({
        @JsonSubTypes.Type(name = "first", value = FirstType.class),
        @JsonSubTypes.Type(name = "second" , value = SecondType.class)
    })
    private List<IType> items;

    //grouping interface
    interface IType {

    }

    @XmlRootElement(name = "first")
    @XmlAccessorType(XmlAccessType.FIELD)
    class FirstType implements IType {
        private String val;
    }

    @XmlRootElement(name = "second")
    @XmlAccessorType(XmlAccessType.FIELD)
    class SecondType implements IType {
        private String testval;
    }
}

但是我的測試無法轉換xml!

public static void main(String[] args) throws Exception {
        String xml =
                "<foo>" +
                        "<first><val>some</val></first>" +
                        "<second><testval>test</testval></second>" +
                "</foo>";


    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();

    ObjectMapper mapper = builder
            .modules(new JaxbAnnotationModule(), new JacksonXmlModule())
            .defaultUseWrapper(false)
            .createXmlMapper(true)
            .build();

    XmlTest unmarshal = mapper.readValue(xml, XmlTest.class);
    System.out.println(unmarshal.items); //prints 'null'
}

項目的結果列表始終為null ,但是為什么呢? 我嘗試了@XmlElements@JsonSubTypes ,但是都沒有用。

我做了一個新的測試:

XSD :(像您一樣)

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/test" xmlns:tns="http://www.example.org/test" elementFormDefault="qualified">

    <element name="foo">
        <complexType>
            <sequence maxOccurs="unbounded">
                <element name="first" type="tns:FirstType"
                    maxOccurs="unbounded" minOccurs="0">
                </element>
                <element name="second" type="tns:SecondType"
                    maxOccurs="unbounded" minOccurs="0">
                </element>
            </sequence>
        </complexType>
    </element>

    <complexType name="FirstType">
        <sequence>
            <element name="val" type="string"></element>
        </sequence>
    </complexType>

    <complexType name="SecondType">
        <sequence>
            <element name="testval" type="string"></element>
        </sequence>
    </complexType>
</schema>

xjc插件生成的JAVA:

Foo.class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "firstAndSecond"
})
@XmlRootElement(name = "foo")
public class Foo {

    @XmlElements({
        @XmlElement(name = "second", type = SecondType.class),
        @XmlElement(name = "first", type = FirstType.class)
    })
    protected List<Object> firstAndSecond;

    /**
     * Gets the value of the firstAndSecond property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the firstAndSecond property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getFirstAndSecond().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link SecondType }
     * {@link FirstType }
     * 
     * 
     */
    public List<Object> getFirstAndSecond() {
        if (firstAndSecond == null) {
            firstAndSecond = new ArrayList<Object>();
        }
        return this.firstAndSecond;
    }

    public Foo withFirstAndSecond(Object... values) {
        if (values!= null) {
            for (Object value: values) {
                getFirstAndSecond().add(value);
            }
        }
        return this;
    }

    public Foo withFirstAndSecond(Collection<Object> values) {
        if (values!= null) {
            getFirstAndSecond().addAll(values);
        }
        return this;
    }

}

FirstType類:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "FirstType", propOrder = {
    "val"
})
public class FirstType {

    @XmlElement(required = true)
    protected String val;

    /**
     * Gets the value of the val property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getVal() {
        return val;
    }

    /**
     * Sets the value of the val property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setVal(String value) {
        this.val = value;
    }

    public FirstType withVal(String value) {
        setVal(value);
        return this;
    }

}

SeconType類:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SecondType", propOrder = {
    "testval"
})
public class SecondType {

    @XmlElement(required = true)
    protected String testval;

    /**
     * Gets the value of the testval property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTestval() {
        return testval;
    }

    /**
     * Sets the value of the testval property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setTestval(String value) {
        this.testval = value;
    }

    public SecondType withTestval(String value) {
        setTestval(value);
        return this;
    }

}

解組可以在JAXB中完美地工作:

String xml = "<foo>" + "<first><val>some</val></first><second><testval>test</testval></second>" + "</foo>";

Unmarshaller un = JAXBContext.newInstance(Foo.class).createUnmarshaller();

Foo unmarshal = (Foo) un.unmarshal(new StringReader(xml));
System.out.println(unmarshal.getFirstAndSecond());
System.out.println(unmarshal.getFirstAndSecond().size());

但這不適用於Jackson2 ...我在網上做了一些研究,我看到了有關Jackson中有關處理XmlElements注釋的錯誤的討論。

您會看到鏈接https://github.com/FasterXML/jackson-databind/issues/374

解決方案是利用:

<dependency>
    <groupId>org.jvnet.jaxb2_commons</groupId>
    <artifactId>jaxb2-basics</artifactId>
</dependency>

並在xsdtojava生成過程中使用-Xsimplify

並為該元素顯式定義一個綁定:

<jaxb:bindings
        xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
        xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
        jaxb:extensionBindingPrefixes="xjc simplify"
        jaxb:version="2.1">

      <jaxb:bindings schemaLocation="xsd/test.xsd">
                <jaxb:bindings multiple="true" node="//xs:element[@name='foo']//xs:complexType//xs:sequence">
                    <simplify:as-element-property/>
                </jaxb:bindings>
      </jaxb:binding>
</jaxb:bindings>

對於每種類型,這將生成兩個單個元素:

private List<FirstType> firstType;
private List<SecondType> secondType;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM