20 March 2011

JAXB Marshalling with Custom Namespace Prefixes

The Problem

  • You have an XML schema with multiple XML namespaces.
  • You generate a JAXB model with xjc.
  • You build a JAXB document model and use the JAXB Marshaller to create XML from the model.
  • You want to override the default namespace prefixes ns1, ns2, ... created by the Marshaller.

Solution 1

You can implement a NamespacePrefixMapper and pass it to the Marshaller

Marshaller m = context.createMarshaller();
    NamespacePrefixMapper mapper = new MyNamespacePrefixMapper();
    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);

  • You need to implement the Mapper.
  • The Marshaller property is implementation dependent.
  • When you use a standalone version of the JAXB Reference Implementation and not the one embedded in Oracle's JDK 6, the property name must be replaced by com.sun.xml.bind.namespacePrefixMapper.

Solution 2

Manually create the package-info.java source file which is normally generated by xjc:

@XmlSchema(namespace = "urn:example.com:foo",
    xmlns = { 
        @XmlNs(namespaceURI = "http://example.com/namespaces/bar", prefix = "bar"),
        @XmlNs(namespaceURI = "urn:example.com:foo", prefix = "")
    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)

package com.example.foo.jaxb;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;

This is enough to make the Marshaller use the prefixes defined in the @XmlNs annotations.

Now you only need to make sure that xjc does not overwrite or duplicate the package-info.java source file by setting the -npa option.

Working with Maven and the maven-jaxb2-plugin, you simply put your customized package-info.java under src/main/java and add the -npa option to the plugin configuration:


Update 21 March 2011: This approach does not work with the JAXB version contained in Oracle's JDK 1.6.0_24. You have to use a more recent version of the JAXB reference implementation by including the following dependency:



Devin said...

Will this work on WebServices as well? I tried manually modifying my package-info.java file and it doesn't effect the SOAP response.

Harald Wellmann said...

I haven't tried this with web services, but I don't see why it shouldn't work as long as you use the proper version of JAXB. It doesn't work with the 2.1 version incorporated in JDK 1.6.0.

danLeon said...

Solution 2 work in JDK 7

Anil said...

I did not have JDK 7 but when i added JAXB 2.2 as mentioned in the post, It worked. Thanks a lot

Anil said...

I was already using package-info.java but it was not adding prefix.
I did not have JDK 7 too, but adding jaxb-impl in pom.xml file solved my issue. Thanks a lot.

Dag Koding said...

Thanks! Helped me a lot.

Manuel Siggen said...

Have a look at the namespace-prefix plugin (http://java.net/projects/jaxb2-commons/pages/Namespace-prefix) which implements solution #2 in an automated way.

Lukas Kummer said...

Great, especially the Ant solution

Sunny said...

Perfect ! it works ....

Ashish Desai said...

This is amazing, finally saved me after hours and hours of exploration. Great work. Thanks a lot

David Lucek said...

Thanks a lot, worked like a charm.

anurag singla said...

Thank a lot it works!!!!!!!

Vinicius Monteiro said...

Hello, I am trying to build a bottom up WS using JAX-WS. wsgen generates the wsdl from the annotated classes.
I would like to remove any prefix, even if possible also the namespace in the request and response.
I tried several things, but just can't get it to work..

Binh Thanh Nguyen said...

Thanks, nice tips