我尝试使用Jackson 2.4.0 XmlMapper
解组以下XML:
<root>
<a/>
<b/>
</root>
......以及以下POJO
class Root {
@JacksonXmlElementWrapper(useWrapping = false)
@JsonSubTypes({
@JsonSubTypes.Type(name = "a", value = POJO_A.class),
@JsonSubTypes.Type(name = "b", value = POJO_B.class)
})
public final List<AbstractPOJO> objects = new ArrayList<>();
}
我还尝试使用JAXB @XmlElements
注释,结果相同,即:
Unrecognized field "a" (class Root), not marked as ignorable (1 known properties: "objects"])
所以杰克逊认为我的名单被称为&#34;对象&#34;而不是&#34; a&#34;和&#34; b&#34;。通常我会使用@JsonProperty("newName")
来解决这个问题,但在这种情况下,我希望通过@JsonSubtypes
或@XmlElements
注释来处理。
由于我无法修改输入XML,我还能做些什么,包括Jackson,Jackson XML还是JAXB注释?
更新:忘了说,问题是反序列化到同一个集合(因为我需要保持顺序,它们可以混合)。在单独的字段中执行它可以正常工作。
答案 0 :(得分:1)
当我尝试peeskillet回答并更换杰克逊为JAXB unmarshaller时,使用@XmlElements
/ @XmlElementRefs
工作(@XmlAnyElement
没有出于某种原因,我得到了{{1而不是我自己的类。)
与杰克逊合作会很高兴,但与此同时,这也是让这项工作顺利进行的方法。
更新:
我做的是:
ElementNSImpl
我还向class Root {
@XmlElements({
@XmlElement(name = "a", type = PojoA.class),
@XmlElement(name = "b", type = PojoB.class)
})
public final List<AbstractPOJO> objects = new ArrayList<>();
}
添加了@XmlRootElement(name = "a")
,但我认为PojoA
@XmlElements
答案 1 :(得分:0)
&#34;由于我无法修改输入XML,我还能做些什么,包括Jackson,Jackson XML还是JAXB注释?&#34;
我对Jackson的Xml功能不太熟悉。但是使用JAXB Unmarshaller
并对注释稍作修改,可以实现这一点。
对于List<AbstractPojo>
,您可以使用@XmlAnyElement(lax = true)
。
使用lax = true
:
如果为true,那么当
XmlAnyElement
知道某个元素与标有JAXBContext
的属性匹配时(例如,那个带有XmlRootElement且具有相同标记名称的类,或者&#39} ; sXmlElementDecl
具有相同的标记名称),unmarshaller将急切地将此元素解组为JAXB对象,而不是将其解组为DOM
这基本上意味着,如果我们使用PojoA
注释PojoB
和@XmlRootElement
并将元素名称作为name
属性(@XmlRootElement(name = "a")
)传递,则按定义,这应该有用。
让我们试一试:
public abstract class AbstractPojo {
// note this class is not annotated. It will be known in the context
// as we're explicitly using the type int the Root class
}
@XmlRootElement(name = "a")
public class PojoA extends AbstractPojo {
}
@XmlRootElement(name = "b")
public class PojoB extends AbstractPojo {
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "root")
public class Root {
@XmlAnyElement(lax = true)
protected List<AbstractPojo> objects;
public List<AbstractPojo> getObjects() {
if (objects == null) {
objects = new ArrayList<>();
}
return this.objects;
}
}
使用以下xml文件进行测试
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a/> <b/> <b/> <a/> <a/> <b/> <b/>
</root>
以下测试程序
public class JaxbTest {
private static final String FILE_NAME = "test.xml";
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
File f = new File(FILE_NAME);
Root root = (Root)unmarshaller.unmarshal(f);
List<AbstractPojo> list = root.getObjects();
for (AbstractPojo p : list) {
System.out.print( p instanceof PojoA ? "a " : "b ");
}
System.out.println();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
我们得到了我们正在寻找的结果。
a b b a a b b
//以及我们为测试编组的xml文件内容
以下是一些很好的资源:
更新
好的,我明白为什么你会得到
ElementNSImpl
。这对我来说不起作用,我得到了ElementNSImpl对象。你知道发生了什么吗?
是的,我知道发生了什么。首先,我用xjc编译了一个xsd,它为我创建了一个ObjectFactory,它声明了元素。这就是为什么它为我工作的原因。
如果您不这样做,那么您应该明确地将PojoA
和PojoB
放入上下文中。
JAXBContext.newInstance(Root.class, PojoA.class, PojoB.class);