Serialize Jaxb Pojos to multiple or different namespaces Serialize Jaxb Pojos to multiple or different namespaces xml xml

Serialize Jaxb Pojos to multiple or different namespaces


This is a good question.

Instead of working on the type-level you could work on the Jaxb node level.There is almost no overhead involved.

The key is creating/accessing JAXBElement (node level elements) out of your business logic classes and customize the XML-Node it represents with an according QName definition.

QName provides several options for customization, ranging from fully qualified namespaces to no namespace at all. The only caveat is that using a namespace without prefix is not possible. Jaxb will use a default namespace if you don't provide one.

Example:

QName elaborateQName = new QName("http://www.another.org/package", "customer", "myNs");QName simpleQName = new QName("customer");JAXBElement jx1 = new JAXBElement(elaborateQName, customer.getClass(), customer);JAXBElement jx2 = new JAXBElement(simpleQName, customer.getClass(), customer);m.marshal(jx1, System.out);m.marshal(jx2, System.out);

This will produce the following output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><myNs:customer xmlns:myNs="http://www.another.org/package">    <id>123</id></myNs:customer><?xml version="1.0" encoding="UTF-8" standalone="yes"?><customer>    <id>123</id></customer>

Using a namespace without prefix is not possible. Trying a QName with empty prefix or the equivalent XMLConstants.DEFAULT_NS_PREFIX as parameter will result in a default prefix (like ns1) being generated:

 // QName defaultNs = new QName("http://www.another.org/package", "customer", "");<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:customer xmlns:ns1="http://www.another.org/package">    <id>123</id></ns2:customer>

Using null as the parameter for prefixyields an Exception:

java.lang.IllegalArgumentException: prefix cannot be "null" when creating a QNameat javax.xml.namespace.QName.<init>(QName.java:251)


How to override the root xmlns attribute with MOXy:

EclipseLink MOXy provides easy customization of JAXB marshalling, including changing the default namespace of your root element. The Object to XML mapping (OXM) for overriding the default namespace is:

<?xml version="1.0"?><xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" version="2.5">    <xml-schema element-form-default="QUALIFIED" namespace="http://www.another.org/package"/></xml-bindings>

To have no default namespace, use <xml-schema element-form-default="UNSET"/> instead.

MOXy Setup:

1) add the library to your project:

<dependency>    <groupId>org.eclipse.persistence</groupId>    <artifactId>org.eclipse.persistence.moxy</artifactId>    <version>2.6.2</version></dependency>

2) Add a jaxb.properties to your object model package to enable MOXy's factory (e.g. src/main/resources/com/sample/entity/jaxb.properties):

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

3) Instantiate your context according to your OXM configuration (in this example, the OXM file is at src/main/resources/com/sample/entity/my-oxm.xml):

Map<String, Source> metadata = Collections.singletonMap("com.sample.entity", new StreamSource(Customer.class.getResourceAsStream("my-oxm.xml")));Map<String, Object> properties = Collections.singletonMap(JAXBContextProperties.OXM_METADATA_SOURCE, metadata);JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {customer.getClass()}, properties);

You can then use marshalling on the JAXBContext as normal. Instantiate separate contexts for each different OXM file you want to use.

Additional customizations with MOXy:

Using MOXy allows you to further customize the marshalling of your entity in the future without changing your object model, effectively making your marshalling logic adhere to the open/closed principle even though you have no explicit Marshaller classes. For instance, if you needed to marshal your Customer object as a Person, you could do this by adding another OXM file:

<?xml version="1.0"?><xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" version="2.5">    <xml-schema element-form-default="QUALIFIED" namespace="http://www.example.com/person"/>    <java-types>        <java-type name="com.sample.entity.Customer">            <xml-root-element name="person"/>            <java-attributes>                <xml-attribute java-attribute="id" name="personId"/>                <xml-element java-attribute="id" xml-path="someOtherId/text()"/>            </java-attributes>        </java-type>    </java-types></xml-bindings>