We'll start with a Customer class that has no namespace information specified:
package example; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { private long id; private String name; @XmlAttribute public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
The following code will be used to run this example:
package example; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Customer customer = new Customer(); customer.setId(123); customer.setName("Jane Doe"); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.marshal(customer, System.out); } }
<customer id="123"> <name>Jane Doe</name> </customer>
Package Level Metadata
We can easily qualify all the elements through the use of the package level annotation @XmlSchema. To specify a package level annotation, create a class called package-info in the desired package (see complete source below for an example). Below we will set a default namespace and specify that by default all elements are namespace qualified.
@XmlSchema( namespace = "http://www.example.org/package", elementFormDefault = XmlNsForm.QUALIFIED) package example; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema;
This will produce the following XML:
<customer xmlns="http://www.example.org/package" id="123"> <name>Jane Doe</name> </customer>
Type Level Metadata
You can override the package level namespace information at the type level using the @XmlType annotation. As per the @XmlSchema annotation elements are still namespace qualified by default, only now the elements inside the Customer type will be qualified with the namespace http://www.example.org/type.
package example; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlRootElement @XmlType(namespace="http://www.example.org/type") public class Customer { private long id; private String name; @XmlAttribute public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
<ns2:customer xmlns="http://www.example.org/type" xmlns:ns2="http://www.example.org/package" id="123"> <name>Jane Doe</name> </ns2:customer>
package example; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlRootElement @XmlType(namespace="http://www.example.org/type") public class Customer { private long id; private String name; @XmlAttribute public long getId() { return id; } public void setId(long id) { this.id = id; } @XmlElement(namespace="http://www.example.org/property") public String getName() { return name; } public void setName(String name) { this.name = name; } }
This will produce the following output:
<ns2:customer xmlns="http://www.example.org/property" xmlns:ns2="http://www.example.org/package" id="123"> <name>Jane Doe</name> </ns2:customer>
Thank you, very good explanation.
ReplyDeleteThis information is very thorough and helpful. However, it seems to be ineffective when preparing a Marshaller object on a Jersey (JSR-311) ContextResolver instance.
ReplyDeleteCan you offer any thoughts?
You need to be sure that you have configured your JAXBContext to use the MOXy implementation. Refer to:
ReplyDeletehttp://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-35.html
Excellent documentation, very clear and thorough. However, in JAXWS, no matter if I put it in package level, or type level, or field level, it only generates a namespace with prefix, not a default namespace like xmlns="..." above. Without a default namespace, I have to specify a namespace for each every element, which is not acceptable. Any idea why the annotation doesn't generate default namespace like above?
ReplyDeleteHi Fee,
ReplyDeleteIf at the package level you use @XmlSchema annotation that specifies a namespace and elementFormDefault=qualified, then JAXB should namespace qualify all elements. JAXB can do this with a default namespace or prefix qualified elements. This choice will not impact the metadata you need to supply.
-Blaise
Hi, i have been looking @ org.eclipse.persistence.oxm.NamespaceResolver and trying to see if there is a way to supply something similar to a com.sun.xml.bind.marshaller.NamespacePrefixMapper so as to specify prefixes for the namespaces other than ns0, ns1 etc.
ReplyDeleteNot strictly needed by many tools, but some of our integration tooling gets rather confused when we keep changing the namespace prefixes (not sure why...)
thanks
David
Hi David,
ReplyDeleteEclipseLink MOXy will use the namespace prefixes as specified on the @XmlSchema annotation.
-Blaise
Hello Blaise,
ReplyDeleteThat appears to work, but it appears to be not intelligent enough to figure out that the namespace prefix are the same, if I have model in two different packages but with the same prefix. Any other ideas on how to "coalsce" the preifx mapping, by default JAXB2 impl appears to be smart enought to do this.
Hello,
ReplyDeleteYou may be referring to the following MOXy bug:
- Bug 343733 - Share namespace declarations (when possible) when model spans packages
-Blaise
Thanks for the very clear guide!!
ReplyDeleteHi i want to use TypeLevel(class) Meta Data without prefix like
ReplyDeleteJane Doe
becuase some java files in my package uses different namespaces...(example for Request message we are using some namespace and Response message we using different namespace)
Hi Vels,
ReplyDeleteI believe your comment may have included an XML fragment that has been lost. Could you send more details through my "Contact Me" page?
-Blaise
Hello Blaise,
ReplyDeleteI am having trouble getting EclipseLink MOXy to work at the moment. I have configured namespace prefixes in package-info.java using @XmlSchema annotation. I have added eclipselink.jar to the classpath and both package-info.java and jaxb.properties files are in the same package as the model classes. However, when I run the program, I get the following error message:
javax.xml.bind.JAXBException: Provider org.eclipse.persistence.jaxb.JAXBContextFactory not found
Any idea what could be the problem?
Many thanks
Khutsi
The issue Khutsi was seeing has been resolved. Below is the link to a Stack Overflow thread with the resolution:
ReplyDelete- http://stackoverflow.com/questions/6817906/cannot-get-eclipselink-moxy-to-work
-Blaise
hi~
ReplyDeleteI've some question.
Itpred class in package a,
Header class in package a,
MessageSender class in package cc,
Identifier class in package a.
only cc package has namespace.
I apply package level annotation.
@XmlSchema(
xmlns = {@XmlNs(prefix = "cc", namespaceURI = "http://www.somesite.com/schema/CC")},
elementFormDefault = XmlNsForm.QUALIFIED
) package cc;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
but result print not include namespace prefix and namespace.
moonumi
I will add class use cc namespace class to cc package.
Why MessageSender does not print ?
but
@XmlSchema(
namespace = "http://www.somesite.com/schema/CC",
xmlns = {@XmlNs(prefix = "cc", namespaceURI = "http://www.somesite.com/schema/CC")},
elementFormDefault = XmlNsForm.QUALIFIED
) package cc;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
result
moonumi
how to specify namespace prefix cc package.
Hello Moonumi,
ReplyDeleteWould you mind providing me more details about your use case through my contact page:
- http://blog.bdoughan.com/p/contact_01.html
I believe some of the details did not survive the formatting of the comments area.
-Blaise
@XmlSchema(
ReplyDeletenamespace="http://www.example.org/package",
elementFormDefault = XmlNsForm.QUALIFIED)
package cdac.medinfo.serialize.poc;
import java.util.Collection;
import java.util.HashSet;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;
import java.io.StringReader;
import java.io.StringWriter;
//@XmlSeeAlso({Employee.class})
@XmlRootElement(name = "ths")
public class TestHashSet {
Collection collection = new HashSet();
public Collection getCollection() {
return collection;
}
public void setCollection(Collection collection) {
this.collection = collection;
}
public static void main(String args[]) throws JAXBException{
TestHashSet ths = new TestHashSet();
/*Employee e = new Employee();
e.setFirstName("Ajay");
e.setId(10);
e.setLastName("Bhojak");
e.setMiddleName("Kumar");*/
//String e = "Ajay Bhojak";
subClass sub=new subClass();
sub.setX(32323);
sub.setZ(323233);
//Collection newCollection = new HashSet();
Collection c=new HashSet();
c.add(sub);
subClass sub1=new subClass();
sub1.setX(787);
sub1.setZ(5512);
c.add(sub1);
ths.setCollection(c);
Class arr[]=new Class[]{TestHashSet.class,subClass.class};
final JAXBContext jaxbContext = JAXBContext.newInstance(arr);
StringWriter writer = new StringWriter();
Marshaller ms = jaxbContext.createMarshaller();
ms.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "xyz.xsd");
ms.marshal(ths, writer);
System.out.println(writer.toString());
final TestHashSet ths1 =
(TestHashSet) jaxbContext.createUnmarshaller().unmarshal(
new StringReader(writer.toString()));
System.out.println("Hello");
}
}
Blaise I have a problem while applying package level annotation, as when I apply it give me a compile time error saying
"Package annotations must be in file package-info.java".
please tell me how do i resolve this problem and I am using eclipse galileo 3.5.
Thank you.
Ajay Bhojak.
Hey I figured out the solution for my problem.
ReplyDeleteThank you.
Ajay Bhojak
Hi Ajay,
ReplyDeleteI'm happy to hear that things are working now. I've updated my post in an attempt to make it more clear for others.
-Blaise
Thanks Blaise.
ReplyDeleteI would surely come to you for any issues if I would not get them solved :-).
Thanks again.
I have some issues regarding unmarshalling on web service side when I do not apply package-info annotation on some specific packages and gives unmarshalling exceptions of local elemen is "some element"
and expected element is "some element".
why does this happen ?
and also when applied NAMESPACE QUALIFIED in package-info it gives the same exception while it works if NAMESPACE UNQUALIFIED annotation is applied.
Thanks.
Ajay Bhojak
Hi Ajay,
ReplyDeleteIf you specify elementFormDefault = XmlNsForm.QUALIFIED then your fields/properties will inherit the namespace qualification from the @XmlSchema or @XmlType annotations. For your use case it appears as though your XML input does not expect all the elements to be namespace qualified.
-Blaise
Hi Blaise,
ReplyDeleteThe post is really helpful. Thanks for sharing with us.
We have a typical problem if you could help us. Here is the link http://stackoverflow.com/q/7445996/517483
If you use EclipseLink JAXB (MOXy) you won't see the extra namespace declaration on the XML corresponding to the DOM Element. I'm not sure why the JAXB reference implementation adds that declaration, but it shouldn't cause you any issues.
ReplyDelete-Blaise
Really useful tutorial, I was going crazy trying to use namespaces with JAXB. Thank you!
ReplyDeleteHi Blaise, nice post ;)
ReplyDeleteOne question, though: I've got a project where JAXB auto generated 2 separate packages for me, those 2 being foo and foo.bar for example. These 2 packages have their own package-info class and each declares a separate namespace using @XmlSchema. In my project a class B from package foo.bar is associated with class A from package foo which is annotated with @XmlRootElement. This is causing the ns2 prefix from foo.bar namespace to be shown in my XML when marshalling class A. The question is: how can I get XML by marshalling the root element, but without the ns2 prefix?
Thanks!
Hi Jonathan,
ReplyDeleteJAXB implementations do there best guess at declaring the namespaces that will be required. Sometimes implementations err on the side of declaring one that might not be needed to avoid the situation of declaring it when it is encountered which could cause it to be declared many times on sibling nodes.
That being said, you can use JAXB with StAX to control the namespaces. Below is a link to an answer I gave on Stack Overflow that used JAXB with StAX to declare namespaces as they were encountered as the default namespace. A similar strategy may help you:
- http://stackoverflow.com/questions/5720501/jaxb-marshalling-xmpp-stanzas/5722013#5722013
-Blaise
Hi Blaise,
ReplyDeleteNot sure this is still active or not. I am having an issue while unmarshalling in jaxb. I am getting an xml in which no name space is present. So when I am unmarshalling it again the XSD that I have, its failing. Is there a way to add a default xmlns before unmarshalling the XML?
Regards
Arnab
Hi Arnab,
DeleteInstead of trying to answer your question in the comment section, I have written a complete example that you can find at the following link:
- Applying a Namespace During JAXB Unmarshal
-Blaise
Hi Blaise,
ReplyDeleteHow can I get namespace prefixed at the attribute level also ?
e.g. ns:id
Thanks
Sudhir
Hi Sudhir,
DeleteI apologize for the delay in responding. The process for XML attributes is very similar to that for elements. There is an attributeFormDefault setting on the @XmlSchema annotation and you can set a namespace on the @XmlAttribute annotation.
-Blaise
I'm having headaches...
ReplyDeleteCannot get JAXB to produce the prefix for the namespace.
I have specified @XmlSchema with @XmlNs mapping and set elementFormDefault to QUALIFIED.
Running on Mac, JDK 1.6.0_37
Hi Paolo,
DeleteHave you read my post on JAXB and Namespace Prefixes?
-Blaise
Hi Blaise,
ReplyDeleteIn JAXB, during un-marshalling I am facing issue, not able to un-mashall properly (response in xml is coming as expected).
I tried to give namespace at type level which were not present in response classes.
But still it is failing.
So what could be issue??
Hi Sachin,
DeleteIf you specify the namespace at the type level, then you still need the @XmlSchema annotation at the package level specifying elementFormDefault = XmlNsForm.QUALIFIED. Otherwise you need to specify the namespaces on each of the @XmlElement annotations.
-Blaise
Fantastic one on namespace...too good..
ReplyDeleteHi Blaise,
ReplyDeleteIf i post an xml to rest easy webservice with attributes i get the below error .Same thing works without the attribute
How to reolve this? Thanks in advance 1!!
Exception
[org.xml.sax.SAXParseException: The end-tag for element type "vcon" must end with a '>' delimiter
here vcon refers to a node with an attribute
[org.xml.sax.SAXParseException: The end-tag for element type "option " must end with a '>' delimiter.]type Status reportmessage javax.xml.bind.UnmarshalException
– with linked exception:
Thank for the article. I wanted to get up and running with JAXB and this exactly answered my questions about namespaces.
ReplyDeleteWritten 2010, stays to be a good article in 2013. Thanx.
ReplyDelete