我想使用jackson
xml mapper将以下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
,但都没有效果。
答案 0 :(得分:0)
我做了一个新测试:
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