Serializing namespaced elements with JAXB

JAXB can be very tricky about namespaces in nested elements. By default, it doesn’t handle namespaces in any way. Is it possible to force namespace prefixes into child elements?

Let’s have a simple class:

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Message")
public class Message {

    protected String recipientId;
    protected String messageBody;

    public String getRecipientId() {
        return recipientId;
    }
    public void setRecipientId(String recipientId) {
        this.recipientId = recipientId;
    }
    public String getMessageBody() {
        return messageBody;
    }
    public void setMessageBody(String messageBody) {
        this.messageBody = messageBody;
    }    

}

Serialization goes along JAXB recommendations:

    Message message = new Message();
    message.setMessageBody("Hi there!");
    message.setRecipientId("name:Suzy");

    JAXBContext jaxbContext = JAXBContext.newInstance(Message.class);      

    JAXBElement<Message> jaxbMessage = new JAXBElement<Message>(new QName("Message"), Message.class, message);

    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    marshaller.marshal(jaxbMessage, System.out);

This prints:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message>
    <messageBody>Hi there!</messageBody>
    <recipientId>name:Suzy</recipientId>
</Message>

How about namespaces?

Just create a package-info.java in the package with class you want to serialize.

@XmlSchema(namespace = "http://schemas.ics.upjs.sk/message")
package sk.upjs.ics.novotnyr.jaxb;

import javax.xml.bind.annotation.XmlSchema;

JAXB will automatically pick up these definitions and serialize your Message with namespace:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message xmlns:ns2="http://schemas.ics.upjs.sk/message">
    <messageBody>Hi there!</messageBody>
    <recipientId>name:Suzy</recipientId>
</Message>

However, this namespace is just a decoration. JAXB has declared the namespace with ns2 prefix, but no elements appear in this namespace.

This is due to default, but somewhat meaningless configuration that does not set the namespaces for elements. We need to change this:

@XmlSchema(namespace = "http://schemas.ics.upjs.sk/message", 
           elementFormDefault=QUALIFIED)
package sk.upjs.ics.novotnyr.jaxb;

import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;

import javax.xml.bind.annotation.XmlSchema;

We have configured the qualified form for serialized elements. Now we can see properly namespaced elements:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message xmlns:ns2="http://schemas.ics.upjs.sk/message">
    <ns2:messageBody>Hi there!</ns2:messageBody>
    <ns2:recipientId>name:Suzy</ns2:recipientId>
</Message>

Finally, we can customize the ugly ns2 prefix and change it to msg

@XmlSchema(namespace = "http://schemas.ics.upjs.sk/message", 
           elementFormDefault=QUALIFIED,
           xmlns = @XmlNs(
                   prefix="msg", 
                   namespaceURI = "http://schemas.ics.upjs.sk/message"))
package sk.upjs.ics.novotnyr.jaxb;

import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;

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

The serialized form will be:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message xmlns:msg="http://schemas.ics.upjs.sk/message">
    <msg:messageBody>Hi there!</msg:messageBody>
    <msg:recipientId>name:Suzy</msg:recipientId>
</Message>

There is one last problem left: the root element Message is in the default namespace, which is not the one with prefix msg. We need to customize this very last feature: but not with annotation.

QName ns = new QName("http://schemas.ics.upjs.sk/message", "Message");
JAXBElement<Message> jaxbMessage = new JAXBElement<Message>(ns, Message.class, message);

Now, everything’s fine:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<msg:Message xmlns:msg="http://schemas.ics.upjs.sk/message">
    <msg:messageBody>Hi there!</msg:messageBody>
    <msg:recipientId>name:Suzy</msg:recipientId>
</msg:Message>

2 thoughts on “Serializing namespaced elements with JAXB

  1. Hello,

    Good tutorial, many thanks, just a question. How do you add xmlns in child element?For instance, regarding your XML example

    Hi there! name:Suzy add xmlns into msg:messageBody element like example below?

    Hi there! name:Suzy

    Thanks in advance

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *