Platinum Partner
java,eclipse,xml,jaxb

JAXB and Namespace Prefixes

In a previous post I covered how to use namespace qualification with JAXB.  In this post I will cover how to control the prefixes that are used.  This is not covered in the JAXB (JSR-222) specification but I will demonstrate the extensions available in both the reference and EclipseLink MOXy implementations for handling this use case

Java Model

The following domain model will be used for this post.  The @XmlRootElement and @XmlElement annotation are used to specify the appropriate namespace qualification.

package blog.prefix;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(namespace="http://www.example.com/FOO")
public class Root {

    private String a;
    private String b;
    private String c;

    @XmlElement(namespace="http://www.example.com/BAR")
    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    @XmlElement(namespace="http://www.example.com/FOO")
    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @XmlElement(namespace="http://www.example.com/OTHER")
    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

}

Demo Code

We will use the following code to populate the domain model and produce the XML.

package blog.prefix;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext ctx = JAXBContext.newInstance(Root.class);

        Root root = new Root();
        root.setA("A");
        root.setB("B");
        root.setC("OTHER");

        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(root, System.out);
    }

}

 

Output

XML like the following is produced by default.  The JAXB implementation has arbitrarily assigned prefixes to the namespace URIs specified in the domain model:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:root
    xmlns="http://www.example.com/BAR"
    xmlns:ns2="http://www.example.com/FOO"
    xmlns:ns3="http://www.example.com/OTHER">
    <a>A</a>
    <ns2:b>B</ns2:b>
    <ns3:c>OTHER</ns3:c>
</ns2:root>

Specify Prefix Mappings with JAXB RI & Metro JAXB

The reference and Metro implementations of JAXB provide a mechanism called NamespacePrefixMapper to control the prefixes that will be assigned to namespaces.

NamespacePrefixMapper

package blog.prefix;

import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper;
//import com.sun.xml.bind.marshaller.NamespacePrefixMapper;

public class MyNamespaceMapper extends NamespacePrefixMapper {

    private static final String FOO_PREFIX = ""; // DEFAULT NAMESPACE
    private static final String FOO_URI = "http://www.example.com/FOO";

    private static final String BAR_PREFIX = "bar";
    private static final String BAR_URI = "http://www.example.com/BAR";

    @Override
    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
        if(FOO_URI.equals(namespaceUri)) {
            return FOO_PREFIX;
        } else if(BAR_URI.equals(namespaceUri)) {
            return BAR_PREFIX;
        }
        return suggestion;
    }

    @Override
    public String[] getPreDeclaredNamespaceUris() {
        return new String[] { FOO_URI, BAR_URI };
    }

}

Demo Code

The NamespacePrefixMapper is set on an instance of Marshaller. I would recommend wrapping the setPropery call in a try/catch block so that your application does not fail if you change JAXB implementations.

package blog.prefix;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext ctx = JAXBContext.newInstance(Root.class);

        Root root = new Root();
        root.setA("A");
        root.setB("B");
        root.setC("OTHER");

        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        try {
            m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", new MyNamespaceMapper());
            //m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespaceMapper());
        } catch(PropertyException e) {
            // In case another JAXB implementation is used
        }
        m.marshal(root, System.out);
    }
 }

Output

The resulting document now uses the NamespacePrefixMapper to determine the prefixes that should be used in the resulting document.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root
    xmlns:bar="http://www.example.com/BAR"
    xmlns="http://www.example.com/FOO"
    xmlns:ns3="http://www.example.com/OTHER">
    <bar:a>A</bar:a>
    <b>B</b>
    <ns3:c>OTHER</ns3:c>
</root>

 

Specify Prefix Mappings with EclipseLink JAXB (MOXy)

MOXy will use the namespace prefixes as they are defined on the @XmlSchema annotation.  In order for MOXy to be able to use the default namespace the elementFormDefault property on the @XmlSchema annotation must be set to XmlNsForm.QUALIFIED.

package-info

XmlSchema(
    elementFormDefault=XmlNsForm.QUALIFIED,
    namespace="http://www.example.com/FOO",
    xmlns={@XmlNs(prefix="bar",
                  namespaceURI="http://www.example.com/BAR")}
)
package blog.prefix;

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

Output

The resulting document now uses the xmlns setting from the @XmlSchema annotation to determine the prefixes that should be used in the resulting document.

<?xml version="1.0" encoding="UTF-8"?>
<root
   xmlns="http://www.example.com/FOO"
   xmlns:ns0="http://www.example.com/OTHER"
   xmlns:bar="http://www.example.com/BAR">
   <bar:a>A</bar:a>
   <b>B</b>
   <ns0:c>OTHER</ns0:c>
</root>

Further Reading

If you enjoyed this post then you may also be interested in:

 

 

From http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}