2017-10-18 105 views
0

我想用jackson XML映射到地圖下面的XML(我有控制的,並從web服務獲得)來一個Java bean:如何使用@XmlElements將不同的對象放入同一個列表中?

<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,這會產生以下豆:

@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,但都沒有工作。

回答

0

的解決方案是利用:xsdtojava生成期間

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

並採用-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; 
0

我做了一個新的測試:

的XSD:

讓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; 
    } 

} 
(像你這樣)的XJC插件生成

<?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> 

的JAVA

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

+0

很好,但因爲寫的,我*不*修改XML輸入,就像我從webservice那裏得到的一樣!我只能重寫我的java bean,它有什麼看起來像不變的XML? – membersound

+0

此外,我想依靠'xsdtojava'代替自己定義jaxb模型,因爲類可能需要在未來再次自動生成。我能否實現兩個列表的自動生成(如你的例子)而不是一個'@ XmlElements'列表? – membersound

+0

好吧,你不能修改你的輸入xml,但你可以檢查你的代碼:你的XmlTest對我來說是不正確的輸入XSD。礦正在工作。 – Tuco

相關問題