2017-10-18 148 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

相关问题