Understanding JAXB #XmlRootElement annotation - java

I am using the tutorial here for understanding JAXB.
When the writer comes to create the root of the document, the writer begins as below:
//This statement means that class "Bookstore.java" is the root-element of our example
#XmlRootElement(namespace = "de.vogella.xml.jaxb.model")
public class Bookstore {
...
}
Although I will be manually generating my classes rather than letting Eclipse do it, I will supply an XSD with my jar file (not packed inside but rather in the folder containing jar file) so that when my application starts, it will validate whether the XML document has been tampered with.
So, in the XSD file, the targetNamespace will be de.vogella.xml.jaxb.model because it was declared above as #XmlRootElement(namespace = "de.vogella.xml.jaxb.model") ?

I recommend using the package level #XmlSchema annotation to specify the namespace qualification for you model. A package level annotation goes in a special class called package-info that contains the exact content as shown below. That annotation will mean that all elements in your document without an explicit namespace given will use that namespace.
org/example/foo/package-info.java
#XmlSchema(
namespace = "http://www.example.org/foo",
elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Overriding the Namespace
You can override the namespace given in the #XmlSchema for all properties in a class using the #XmlType annotation.
You can override the namespace for a given element using the namespace property on the #XmlRootElement or #XmlElement annotation.
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

#XmlRootElement annotation can be used to map a class or enum type to XML type.
When a top level class or an enum type is annotated with the #XmlRootElement annotation, then its value is represented as XML element in an XML document.
Follow the example given below to get more idea:
Associate an element with XML Schema type
// Example: Code fragment
#XmlRootElement
class Point {
int x;
int y;
Point(int _x,int _y) {x=_x;y=_y;}
}
//Example: Code fragment corresponding to XML output
marshal( new Point(3,5), System.out);
<!-- Example: XML output -->
<point>
<x> 3 </x>
<y> 5 </y>
</point>

Related

Jaxb java set namespace to all elements

I have a Java class:
#XmlRootElement(name = "a")
public class a {
#XmlElementWrapper
public Component[] components;
public String content;
}
And an XML file: test.xml and XSD file which is generated using the JAXBContext::generateSchema method.
An example XML file:
<a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://example.com"
xsi:schemaLocation="http://example.com file://...schema.xsd">
</a>
If I want to unmarshal it, I need to add namespace = "http://example.com" to all elements.
Otherwise, I will get a javax.xml.bind.UnmarshalException as this.
However, If I have a lot of classes in many different packages, or some fields that are annotated with #XmlElements has a lot of #XmlElement children.
I need to copy and paste namespace = "http://example.com" uncountable times, it is dumb and meaningless. Are there some methods that allow me to only type the namespace once?
You can try to add file: package-info.java to your package.
#javax.xml.bind.annotation.XmlSchema(namespace =
"http://webservices.com/myws",
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "ws",
namespaceURI="http://webservices.com/myws")
}
)
package mypackage;

JAXB forcing namespace URI - why does it expect certain namespace even when it was not defined?

I have mystery when trying to unmashall XML document:
unexpected element (uri:"http://www.xxx/xsd/ems/batchreq", local:"batchParams"). Expected elements are <{}msgCollection>,<{}batchParams>]
Element should not come with namespace - it does not have in in xml, nor in java class, yet it seems that when it is parsed, it gets namespace uri - and for bigger mystery, elements that have namespace do not seem to expect it.
Why?
Adding namespace to #XmlElement helps, but then it seems that it would have to be defined for every single element - that is unacceptable solution. Why is namespace not inherited by child elements?
Root class is:
#XmlRootElement(name = "batch", namespace = "http://www.xxx/xsd/ems/batchreq")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "batch", namespace = "http://www.xxx/xsd/ems/batchreq", propOrder = { "batchParams", "msgCollection" })
public class Batch {
#XmlAttribute(required = true)
private String batchName;
#XmlElement(name = "batchParams", required = true)
private BatchParams batchParams;
#XmlElement(name = "msgCollection", required = true)
private Msgs msgCollection;
...
Offending member class is:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "batchParams", namespace = "http://www.xxx/xsd/ems/batchreq", propOrder = { "msgCount", "dateCreated" })
public class BatchParams {
#XmlElement()
private Long msgCount;
#XmlElement()
private Date dateCreated;
public Long getMsgCount() {
...
Xml document is:
<?xml version="1.0" encoding="UTF-8"?>
<batch xmlns="http://www.xxx/xsd/ems/batchreq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xxx/xsd/ems/batchreq ./ems_msg_batchreq.xsd" batchName="d" msgType="ems_sendemsg_batchreq" sourceSystem="1">
<batchParams>
<msgCount>1</msgCount>
<dateCreated>2014-12-03T12:00:00</dateCreated>
</batchParams>
<msgCollection xmlns="http://www.xxx/xsd/ems/req">
<msg msgType="ems_sendemsg_msg" sourceSystem="1" dataSourceSystem="1">
...
</msg>
</msgCollection>
</batch>
Element should not come with namespace - it does not have in in xml,
nor in java class, yet it seems that when it is parsed, it gets
namespace uri - and for bigger mystery, elements that have namespace
do not seem to expect it.
The XML in your question declares http://www.xxx/xsd/ems/batchreq as the default namespace. This means that each element in your XML that isn't assigned to a different namespace wil be part of that one.
<?xml version="1.0" encoding="UTF-8"?>
<batch xmlns="http://www.xxx/xsd/ems/batchreq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xxx/xsd/ems/batchreq ./ems_msg_batchreq.xsd" batchName="d" msgType="ems_sendemsg_batchreq" sourceSystem="1">
<batchParams>
<msgCount>1</msgCount>
<dateCreated>2014-12-03T12:00:00</dateCreated>
</batchParams>
<msgCollection xmlns="http://www.xxx/xsd/ems/req">
<msg msgType="ems_sendemsg_msg" sourceSystem="1" dataSourceSystem="1">
...
</msg>
</msgCollection>
</batch>
Adding namespace to #XmlElement helps, but then it seems that it would
have to be defined for every single element - that is unacceptable
solution.
You can use the package level #XmlSchema annotation to map a default namespace qualification. This goes on a source file called package-info.java with only the content shown below. You will need to change the package name to match your domain model.
#XmlSchema(
namespace = "http://www.xxx/xsd/ems/batchreq",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Why is namespace not inherited by child elements?
Namespace specification in JAXB does get inherited, just not in the way that you tried.
The package level #XmlSchema annotation provides a way to specify the default namespace that should be inherited by all elements corresponding to classes and properties within that package.
The type level #XmlType annotation provides a way to specify the namespace inherited by all properties on this class. This over rides the namespace information specified on the #XmlSchema annotation.
Finally namespace can be specified on the #XmlRootElement, #XmlElement annotations (and some others). The namespaces specified here are for that element only.
For More Information
I have written more about this use case on my blog:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

How to unmarshall when you have xml namespace?

I am trying to unmarshall an xml using a namespace to create an object from it. I am getting exceptions that the element is not expected. Here is what I've got.
#XmlRootElement(name="package")
#XmlAccessorType(XmlAccessType.NONE)
public class DenPackage {
.....
}
The xml:
<?xml version="1.0" encoding="ASCII"?>
<pkg:package xmlns:pkg="http://www.leap.com/rest/package">
</pkg:package>
The exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.leap.com/rest/package", local:"package"). Expected elements are <{}package>
Should the #XmlRootElement(name="package") be the thing that changes? Or if you know more than I do, any help is greatly appreciated. Thanks
Use Case #1 - All Elements Are Namespace Qualified
If all (or most) of the elements in your document are going to be qualified with the same namespace use the #XmlSchema annotation to specify the namespace qualification. #XmlSchema is a package level annotation so it goes on a special class called package-info that looks something like. The combination of specifying a namespace and elementFormDefault=XmlNsForm.QUALIFIED means that this namespace will be applied to all elements that haven't overridden the namespace.
package-info.java
#XmlSchema(
namespace = "http://www.leap.com/rest/package",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.leap.rest.pkg;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Use Case #2 - Just the Root Element Is Namespace Qualified
If just the root element is namespace qualified then use the #XmlRootElement annotation.
#XmlRootElement(name="package", namespace = "http://www.leap.com/rest/package")
#XmlAccessorType(XmlAccessType.NONE)
public class DenPackage {
.....
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Just add the namespace attribute:
#XmlRootElement(name="package", namespace = "http://www.leap.com/rest/package")
You need to define pkg namespace on your class like this:
#XmlRootElement(name="package" namespace = "http://www.leap.com/rest/package")
#XmlAccessorType(XmlAccessType.NONE)
public class DenPackage {
.....
}
Remember, if you have child elements in your xml (not shown in your sample) and they also belong to namespace, then define namespace for them as well as namespace is not "inherited" by the fields on the bound class

XJC doesn't generate the #XmlElement with namespace?

I want to parse data using JAXB for the the following XSD schema http://www.uniprot.org/support/docs/uniprot.xsd .
A typical XML for this looks like this: http://www.uniprot.org/uniprot/Q8NEJ9.xml
My Classes were generated using:
xjc http://www.uniprot.org/support/docs/uniprot.xsd
I cannot get a JAXB unmarshaller to parse this data.
xmlInputFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);
XMLEventReader rx=xmlInputFactory.createXMLEventReader(in);
final QName uEntry=new QName("http://uniprot.org/uniprot","entry");
while(rx.hasNext())
{
XMLEvent evt=rx.peek();
if(!(evt.isStartElement() && evt.asStartElement().getName().equals(uEntry)))
{
rx.next();
continue;
}
JAXBElement<Entry> jaxbElement=uniprotUnmarshaller.unmarshal(rx, Entry.class);
Entry entry= jaxbElement.getValue();
(...)
}
Each instance of 'entry' remains empty. When an entry is marshaled to stderr, I get something like:
<ns2:entry xmlns:ns2="http://uniprot.org/uniprot" dataset="Swiss-Prot" created="2011-06-28+01:00" modified="2011-09-21+01:00" version="20"/>
I think it's because xjc ignores the namespaces. It generates:
#XmlRootElement(name = "entry")
public class Entry {
instead of (?)
#XmlRootElement(name = "entry",namespace="http://uniprot.org/uniprot")
public class Entry {
How can I fix this ?
A package-info class containing the #XmlSchema annotation will be generated for you. Since a namespace was specified along with elementFormDefault equal to XmlNsForm.QUALIFIED all annotations corresponding to XML elements without a namespace parameter specified will belong to this namespace.
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2013.07.22 at 10:14:54 AM EDT
//
#javax.xml.bind.annotation.XmlSchema(namespace = "http://uniprot.org/uniprot", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.uniprot.uniprot;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Getting namespace of an #XmlType at runtime

I'm trying to output the schemaLocation attribute properly when marshalling an xjc-generated class instance. The root element class looks like:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"rootElement"
})
#XmlRootElement(name = "ROOTELEMENT")
public class ROOTELEMENT {
// Members
}
I see there's a package-info.java class sitting in the package where all generated classes are, with the following contents:
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://my.own.namespace",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package my.generated.classes.package;
The answer to JAXB XJC code generation - “schemaLocation” missing in xml generated by Marshaller proposes setting the Marshaller.JAXB_SCHEMA_LOCATION property, and it indeed works:
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://my.own.namespace my_schema.xsd");
But I'd like to avoid typing the namespace, as in:
String namespace = getNamespace(rootElementInstance);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, namespace + " my_schema.xsd");
I'd appreciate any tips on how to implement the getNamespace() function.
EDIT: I've seen that the XmlRootElement and XmlType annotations have the namespace() method, that seems to be what I'm after (actually, they seem to delegate on the XmlSchema provided in package-info.java). However, I cannot get an instance of ROOTELEMENT casted to any of these types.
You need to grab a hand on your package (for example using ROOTELEMENT.class.getPackage() if ROOTELEMENT is in the package you want). Then you can simply process it as follow:
Package package = // Here retrieve the package;
String namespace = package.getAnnotation(XmlSchema.class).namespace();
...etc...

Categories

Resources