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
Related
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;
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
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>
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...
When i create a jaxbcontext with all my classes, jaxb build xml for a class with a namespace from other class.
If i pass to jaxbcontext only one class it work fine.
My classes are generated by xjc.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
})
#XmlRootElement(name = "eReq")
public class EReq {
...
And when i pass only this class to jaxbcontext the output is following.
<eReq><status>UNBLOCKED</status></eReq>
But i put all my classes into jaxb context output will be like this:
<eReq xmlns:ns2="myns1" xmlns:ns3="myns2" xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/"><status>UNBLOCKED</status></eReq>
This is namespaces from my other classes. Why jaxb put it to this class?
Why jaxb put it to this class?
Because the JAXB context contains the superset of all namespaces that it's created with, and it just puts them all in each document it generates.
It does this because the namespaces need to be added to the root element (to avoid hugely wasteful re-declaration of namespaces on each child element), and it doesn't know in advance which namespaces are required for any given set of bound objects (JAXB supports incremental serialization).
So the JAXB runtime probably could avoid doing that; but it doesn't.
If you don't like it, then you need to build multiple contexts.