JAXB @XmlAdapter用于任意XML

我有一个org.w3c.dom.Element ,我从我的XmlAdapter返回自定义@XmlElement ,我想将它作为任意XML包含在JAXB对象中(我知道我必须手工制作XSD)。 但是,JAXB抱怨道

 org.w3c.dom.Element is an interface, and JAXB can't handle interfaces. 

显然,w3c XML类型不支持Java类型 ,这是一种耻辱。 但javax.xml.transform.Result ,当我使用显然支持的javax.xml.transform.Result时,我得到了同样的错误。

如何在JAXB中包含任意XML元素作为元素?

注意:根据https://forums.oracle.com/thread/1668210我也试过了

 MessageFactory factory = MessageFactory.newInstance(); message = factory.createMessage(); SOAPElement element = message.getSOAPBody().addDocument(doc); 

但这也给出了同样的错误。

TL; DR

只要将值类型指定为Object (而不是Element ),就可以使用XmlAdapter将域对象转换为org.w3c.dom.Element的实例。


以下是一个完整的例子。

XmlAdapter

java.lang.Object类型的字段/属性将未知内容保留为DOM节点。 您可以通过在XmlAdapter值类型指定为Object来在您的用例中利用它。 您需要确保从marshal方法返回的根元素与@XmlElement注释定义的字段/属性匹配。

 import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.parsers.*; import org.w3c.dom.*; public class BarAdapter extends XmlAdapter{ private DocumentBuilder documentBuilder; public BarAdapter() { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); documentBuilder = dbf.newDocumentBuilder(); } catch(Exception e) { // TODO - Handle Exception } } @Override public Bar unmarshal(Object v) throws Exception { Bar bar = new Bar(); Element element = (Element) v; bar.value = element.getTextContent(); return bar; } @Override public Object marshal(Bar v) throws Exception { Document document = documentBuilder.newDocument(); Element root = document.createElement("bar"); root.setTextContent(v.value); return root; } } 

Java模型

@XmlJavaTypeAdapter注释用于引用XmlAdapter

 import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Foo { @XmlJavaTypeAdapter(BarAdapter.class) private Bar bar; } 

酒吧

 import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class Bar { String value; } 

演示代码

演示

由于创建DocumentBuilderFactory需要付出代价,因此我们可以通过在Marshaller上设置实例来利用JAXB处理XmlAdapter的有状态实例的能力。

 import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Foo.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/forum18272059/input.xml"); Foo foo = (Foo) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); marshaller.setAdapter(new BarAdapter()); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(foo, System.out); } } 

input.xml中/输出

   Hello World