JAXB @XmlAdapter for custom XML

I have an org.w3c.dom.Element that I am returning from my XmlAdapter for a custom @XmlElement , and I would like to include it as part of the JAXB object as arbitrary XML (I know that I have to process XSD). However, JAXB complains about

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

Apparently, w3c XML types are not supported as Java types , which is a shame. But other than that, I get the same error when I use javax.xml.transform.Result , which is apparently supported.

How to include arbitrary XML elements as elements in JAXB?

Note: according to https://forums.oracle.com/thread/1668210 I also tried

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

but it also gives the same error.

+4
source share
1 answer

TL DR

You can have an XmlAdapter that converts your domain object into an instance of org.w3c.dom.Element , while you specify the value type as Object (not Element ).


The following is a complete example.

XMLAdapter

A field / property of type java.lang.Object will store unknown content as DOM nodes. You can use this in your use case by specifying the value type in the XmlAdapter as Object . You will need to make sure that the root element returned by the marshal method matches the field / property defined by the @XmlElement annotation.

 import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.parsers.*; import org.w3c.dom.*; public class BarAdapter extends XmlAdapter<Object, Bar>{ 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 Model

Foo

The @XmlJavaTypeAdapter annotation @XmlJavaTypeAdapter used to refer to the 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; } 

Bar

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

Demo code

Demo

Since there is the cost of creating a DocumentBuilderFactory, we can use the capabilities of JAXB to process instances with XmlAdapter state correction by installing the instance on Marshaller.

 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 / output

 <?xml version="1.0" encoding="UTF-8"?> <foo> <bar>Hello World</bar> </foo> 
+6
source

Source: https://habr.com/ru/post/1497413/


All Articles