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>
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
Hi there! I’d love to help, but your example XML got mangled. Can you post it via pastebin?