How to unmarshall when you have xml namespace? - java

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

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

Missing namespace in the javas generated by wsimport

When using wsimport the "standard" way:
wsimport.exe -d C:/temp/generatedClasses -s C:/temp/sourceFiles C:/temp/myWsdl.wsdl
I get source files generated like this:
#XmlRootElement(name = "PingRequest")
public class PingRequest{
Last time the classes were generated the same WSDL/ XSDs should have been used and generated a output like this:
#XmlRootElement(name = "PingRequest", namespace = "http://me.foo.bar/any/")
public class PingRequest {
So the schemas namespace was included as attribute of the annotation. Since the generated class package-info.java has the following entry:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://me.foo.bar/any", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
I assume adding the namespace-attribute is a done by configuration of wsimport/ jaxb schema compiler.
Could anyone explain me how to archive the namespace attribute beeing included?
Update: As Blaise answered correctly (described in the blog-link) the generated file package-info.java defines the namespace for all classes/ types inside the according package. Above example is obsolete if always the same namespace is included per #RootElement. Setting namespaces on #RootElement level may be used to have a certain #RootElement have its own namespace (which in case of wsimport should happen automaticially).
Very many thanks for any suggestions
What i tried:
used google, found https://www.java.net/node/681149 (exaclty my question from back in 2008) with no answer :(
read wsimport/ jaxb schema compiler options, tried out various that only controlled package ouput
read 12 similar question/ answer that poped up when i typed in the title of this question
Closest i found that has something to do with the namespaces was to have 'elementFormDefault="qualified' specified in both the XSD itself and the import part inside the WSDL which i have done.
Specifying the following annotation at the package level, and not specifying the namespace on all the #XmlElement/#XmlRootElement annotations.
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://me.foo.bar/any",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
Is the equivalent to not having #XmlSchema and adding the namespace parameter to all the #XmlElement/#XmlRootElement annotations. They will produce/consume the same XML documents.
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Understanding JAXB #XmlRootElement annotation

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>

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