JAXB2 unmarshalling xsd:anyType Error - jaxb

I am encountering a problem unmarshalling data containing xsd:anyType(ur-type) objects such as:
<xsd:element name="Options" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Key" minOccurs="0"/>
<xsd:element name="Next" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
JAXB2 creates the following Java class for the element above;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"key",
"next"
})
public static class Options {
#XmlElement(name = "Key")
protected Object key;
#XmlElement(name = "Next")
protected Object next;
/**
* Gets the value of the key property.
*
* #return
* possible object is
* {#link Object }
*
*/
public Object getKey() {
return key;
}
/**
* Sets the value of the key property.
*
* #param value
* allowed object is
* {#link Object }
*
*/
public void setKey(Object value) {
this.key = value;
}
/**
* Gets the value of the next property.
*
* #return
* possible object is
* {#link Object }
*
*/
public Object getNext() {
return next;
}
/**
* Sets the value of the next property.
*
* #param value
* allowed object is
* {#link Object }
*
*/
public void setNext(Object value) {
this.next = value;
}
}
The marshalling works but when unmarshalling, it throws the following exception;
org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
at org.apache.xerces.dom.CoreDocumentImpl.checkNamespaceWF(Unknown Source)
at org.apache.xerces.dom.ElementNSImpl.setName(Unknown Source)
at org.apache.xerces.dom.ElementNSImpl.<init>(Unknown Source)
at org.apache.xerces.dom.CoreDocumentImpl.createElementNS(Unknown Source)
at org.apache.xml.utils.DOMBuilder.startElement(DOMBuilder.java:322)
at org.apache.xalan.transformer.TransformerIdentityImpl.startElement(TransformerIdentityImpl.java:1072)
at com.sun.xml.bind.v2.runtime.unmarshaller.DomLoader.startElement(DomLoader.java:118)
at com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:73)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:455)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:433)
at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:71)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:137)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:240)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:277)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:246)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:277)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:246)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:277)
at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:246)
at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:123)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:314)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:297)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:107)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:581)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:568)
...
I am using;
JDK 1.6.0_19
spring-oxm-3.0.5.RELEASE.jar
jaxb-impl-2.1.7.jar
jaxb-api-2.1.jar
com.springsource.org.apache.xalan-2.7.0.jar
com.springsource.org.apache.xerces-2.8.1.jar
Thanks,
Henry Kim

Related

JAXB not generating field for redefined attribute

I have an xsd that redefines a complex type to add a sequence:
<xs:redefine>
<xs:complexType name="data-extension.type">
<xs:complexContent mixed="true">
<xs:extension base="data-extension.type">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
However when I generate the code for my xsd using JAXB, the DataExtensionType class does not has a field for the sequence.
Am I missing something in the xsd or the JAXB generation parameters?
Edit:
This is the generated Java:
/**
* <p>Java class for data-extension.type complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="data-extension.type">
* <complexContent>
* <extension base="{http://graphml.graphdrawing.org/xmlns}data-extension.type">
* <redefine>
* <complexType name="data-extension.type">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* </restriction>
* </complexContent>
* </complexType>
* </redefine>
* <sequence>
* <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </extension>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "data-extension.type", namespace = "http://graphml.graphdrawing.org/xmlns")
#XmlSeeAlso({
DefaultType.class,
DataType.class
})
#Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2018-03-02T02:29:07+00:00", comments = "JAXB RI v2.2.8-b130911.1802")
public class DataExtensionType
extends OriginalDataExtensionType
{
}
The comment suggest the sequence was found during parsing.
I was expecting to see a List<Object> any (or similar) and its getter to be generated. The supper class has a contents field, but its type is String.
Edit 2:
The OriginalData class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"content"
})
#XmlSeeAlso({
DataExtensionType.class
})
#Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2018-03-02T02:29:07+00:00", comments = "JAXB RI v2.2.8-b130911.1802")
public class OriginalDataExtensionType {
#XmlValue
#Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2018-03-02T02:29:07+00:00", comments = "JAXB RI v2.2.8-b130911.1802")
protected String content;
/**
*
* Extension mechanism for the content of <data> and <default>.
* The complex type data-extension.type is empty per default.
* Users may redefine this type in order to add content to
* the complex types data.type and default.type which are
* extensions of data-extension.type.
*
*
* #return
* possible object is
* {#link String }
*
*/
#Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2018-03-02T02:29:07+00:00", comments = "JAXB RI v2.2.8-b130911.1802")
public String getContent() {
return content;
}
/**
* Sets the value of the content property.
*
* #param value
* allowed object is
* {#link String }
*
*/
#Generated(value = "com.sun.tools.internal.xjc.Driver", date = "2018-03-02T02:29:07+00:00", comments = "JAXB RI v2.2.8-b130911.1802")
public void setContent(String value) {
this.content = value;
}
}
At first I also expected that the contents field would be the sequence.

JAXB avoid JAXBElement<?>

I want to generate Java classes with JAXB from a XSD file.
The problem is, that I always get a few classes like this one (namespace removed):
public static class Action {
#XmlElementRefs({
#XmlElementRef(name = "ReportStateCanceled", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportDate", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportStatePreliminary", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "DocumentID", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportStateNotValidated", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "CaseNo", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "PatientID", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "DocumentKey", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportTime", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportHeading", namespace = "http://...", type = JAXBElement.class, required = false),
#XmlElementRef(name = "ReportStateComplete", namespace = "http://...", type = JAXBElement.class, required = false)
})
protected List<JAXBElement<?>> documentKeyOrDocumentIDOrPatientID;
#XmlAttribute(name = "name")
protected String name;
#XmlAttribute(name = "Query")
protected String query;
/**
* Gets the value of the documentKeyOrDocumentIDOrPatientID property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the documentKeyOrDocumentIDOrPatientID property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getDocumentKeyOrDocumentIDOrPatientID().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {#link JAXBElement }{#code <}{#link Template.Page.Actions.Action.ReportDate }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
* {#link JAXBElement }{#code <}{#link Template.Page.Actions.Action.ReportTime }{#code >}
* {#link JAXBElement }{#code <}{#link String }{#code >}
*
*
*/
public List<JAXBElement<?>> getDocumentKeyOrDocumentIDOrPatientID() {
if (documentKeyOrDocumentIDOrPatientID == null) {
documentKeyOrDocumentIDOrPatientID = new ArrayList<JAXBElement<?>>();
}
return this.documentKeyOrDocumentIDOrPatientID;
}
/**
* Gets the value of the name property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the query property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getQuery() {
return query;
}
/**
* Sets the value of the query property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setQuery(String value) {
this.query = value;
}
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <simpleContent>
* <extension base="<http://www.w3.org/2001/XMLSchema>string">
* <attribute name="dateFormat" type="{http://www.w3.org/2001/XMLSchema}string" />
* </extension>
* </simpleContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"value"
})
public static class ReportDate {
#XmlValue
protected String value;
#XmlAttribute(name = "dateFormat")
protected String dateFormat;
/**
* Gets the value of the value property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setValue(String value) {
this.value = value;
}
/**
* Gets the value of the dateFormat property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getDateFormat() {
return dateFormat;
}
/**
* Sets the value of the dateFormat property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setDateFormat(String value) {
this.dateFormat = value;
}
}
As you can see JAXB uses JAXBElement. Such classes are unuseable for me.
After some research I found out that JAXB has troubles with nillable="true" and minOccurs="0" together, but I do not use nillable anywhere. Tough I am sure, that the problem is related with the minOccurs and maxOccurs.
Even if I would know the exact problem it would be a problem because I get the XSD from an external person and I am not allowed to modify it.
The XSD snippet:
<xs:element name="Action" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="DocumentKey" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="DocumentID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="PatientID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="CaseNo" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportHeading" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportDate" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" >
<xs:attribute name="dateFormat" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="ReportTime" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string" >
<xs:attribute name="timeFormat" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="ReportStateNotValidated" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStatePreliminary" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStateComplete" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ReportStateCanceled" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="Query" type="xs:string" />
</xs:complexType>
</xs:element>
So I searched for another solution.
I always came to the conclusion that I could solve the problem if add a jaxb-binding.xml when I am generating the classes from the XSD.
I tried some bindings, but it never worked.
With this binding I get less JAXBElements, but I get interfaces instead of classes.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="2.0">
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings generateValueClass="false" generateElementProperty="false" >
<xjc:simple />
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
</xs:schema>
And now I am asking if anyone knows a solution?
The best solution would be if someone provides me a working jaxb-binding.xml.
I am using version 2.2.4-2 of the xjc compiler.
Thank you in advance!
The Problem
The problem is that your xs:choice element has maxOccurs="unbounded".
<xs:choice minOccurs="0" maxOccurs="unbounded">
JAXB Spec Reference
Because of this JAXB can't generate individual properties for each option in the choice structure. See "6.12.6 Bind a repeating occurrence model group" of the JAXB 2.2 (JSR-222) specification for more details:
https://jcp.org/en/jsr/detail?id=222
Why it's a Problem
The following XML fragment is valid according to your XML schema and needs to be able to be represented in the generated object model.
<Action>
<DocumentID/>
<PatientID/>
<PatientID/>
<DocumentID/>
</Action>
Work Around
If you ever really don't like a class that JAXB generates you can create your own and specify via a bindings file that JAXB should use it instead of creating a new one.
<jxb:bindings schemaLocation="yourSchema.xsd">
<jxb:bindings node="//xs:element[#name='Action']">
<jxb:class ref="com.example.Action"/>
</jxb:bindings>
</jxb:bindings>
I wrote the Simpify plugin exactly for this problem.
<xs:schema ...
xmlns:simplify="http://jaxb2-commons.dev.java.net/basic/simplify"
jaxb:extensionBindingPrefixes="... simplify">
<xs:complexType name="typeWithReferencesProperty">
<xs:choice maxOccurs="unbounded">
<xs:element name="a" type="someType">
<xs:annotation>
<xs:appinfo>
<simplify:as-element-property/>
</xs:appinfo>
</xs:annotation>
</xs:element>
<xs:element name="b" type="someType"/>
</xs:choice>
</xs:complexType>
will give you
#XmlElement(name = "a")
protected List<SomeType> a;
#XmlElement(name = "b")
protected List<SomeType> b;
instead of
#XmlElementRefs({
#XmlElementRef(name = "a", type = JAXBElement.class),
#XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;
Disclaimer: I'm the author.

What should I change to get a different element name on the response XSD of an automatically generated JAX-WS?

I have created a Web Service in Java with JAX-WS. It is a simple one that just returns an uppercased version of a String:
#WebService(endpointInterface = "mod2.Mod2")
public class Mod2Impl implements Mod2 {
#Override
public String mod2(String x) {
return x.toUpperCase();
}
}
and its interface:
#WebService
public interface Mod2 {
#WebMethod
String mod2(String x);
}
JAX generates the mod2.jaxws package for me with the relevant classes. The response is like this:
#XmlRootElement(name = "mod2Response", namespace = "http://mod2/")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "mod2Response", namespace = "http://mod2/")
public class Mod2Response {
#XmlElement(name = "return", namespace = "")
private String _return;
/**
*
* #return
* returns String
*/
public String getReturn() {
return this._return;
}
/**
*
* #param _return
* the value for the _return property
*/
public void setReturn(String _return) {
this._return = _return;
}
}
When deployed it generates the proper WSDL file with an import to an XSD. This is the XSD:
<xs:schema xmlns:tns="http://mod2/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://mod2/">
<xs:element name="mod2" type="tns:mod2"/>
<xs:element name="mod2Response" type="tns:mod2Response"/>
<xs:complexType name="mod2">
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="mod2Response">
<xs:sequence>
<xs:element name="return" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Now, what I want is to change the element named "return" in the XSD for whatever I want. I have tried changing the #XmlElement(name = "return", namespace = "") in the Mod2Response class but this throws the following error:
GRAVE: WSSERVLET11: failed to parse runtime descriptor: javax.xml.ws.WebServiceException: class mod2.jaxws.Mod2Response do not have a property of the name return
What is it I have to change to achieve this?
I have found the answer here.
I added #WebResult(name="mod2Result") to my interface:
#WebService
public interface Mod2 {
#WebMethod
#WebResult(name="mod2Result")
String mod2(String x);
}
and then run the wsgen again. Which generated the following Response:
#XmlRootElement(name = "mod2Response", namespace = "http://mod2/")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "mod2Response", namespace = "http://mod2/")
public class Mod2Response {
#XmlElement(name = "mod2Result", namespace = "")
private String mod2Result;
/**
*
* #return
* returns String
*/
public String getMod2Result() {
return this.mod2Result;
}
/**
*
* #param mod2Result
* the value for the mod2Result property
*/
public void setMod2Result(String mod2Result) {
this.mod2Result = mod2Result;
}
}
which also has the #XmlElement(name = "mod2Result") as stated by Joshi but it also changed the name of variable, setter and getter. I tried with the #XmlElement straight in the Response class only with no success.
#WebService
public interface Mod2 {
#WebMethod
#XMLElement(name="returnChanged")
String mod2(String x);
}
You can try this code in your web service. This is a pseudo code.

How do create enum with Eclipse XSD editor

I'm creating an XSD for common web service types that will be used in WSDLs. One of the common types I need is an enum.
My problem is when I execute wsimport the artifact generated is a class not an enum.
I'm using Eclipse Indigo's XSD and WSDL editor. This is what I do in design mode to create my enum:
Create new Complex Type (ResponseCodeType)
Add new string element (code) in ResponseCodeType
In the constraints property of code, I add the following constraint values: SUCCESS, WARNING, ERROR, FATAL
What am I doing wrong?
XSD source
<complexType name="ResponseCodeType">
<sequence>
<element name="code">
<simpleType>
<restriction base="string">
<enumeration value="SUCCESS"></enumeration>
<enumeration value="WARNING"></enumeration>
<enumeration value="ERROR"></enumeration>
<enumeration value="FATAL"></enumeration>
</restriction>
</simpleType>
</element>
</sequence>
</complexType>
Java source for artifact produced by wsimport
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ResponseCodeType", propOrder = {
"code"
})
public class ResponseCodeType {
#XmlElement(required = true)
protected String code;
/**
* Gets the value of the code property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getCode() {
return code;
}
/**
* Sets the value of the code property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setCode(String value) {
this.code = value;
}
}
I figured it out. When I tried designing my enum I created a complex type with an element having the constraints I needed (SUCCESS, INFO, WARN, ect).
What I did instead was to create a simple type with a string element having the constraints (ResponseCode). Then I created a complex type (ResponseCodeType) with an element of ResponseCode.
When I executed wsimport, it generated ResponseCode as an enum and ResponseCodeType class with a ResponseCode attribute.
If anyone has a better approch please comment or provide a better answer.

Cast JAXB2 generated object to JAXBElement?

I have 2 sets of XSD's, one that generates RPC based calls, and another that defines the product specific methods. The RpcType object (generated by JAXB2) has a 'setRpcOperation' method defined by:
RpcType.setRpcOperation(JAXBElement<? extends RpcOperationType>)
That 'RpcOperation' object should be the 'specific product method' described above. One example is (also generated by JAXB2):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "get-user-stats", propOrder = {
"reset"
})
public class GetUserStats {
protected Boolean reset;
/**
* Gets the value of the reset property.
*
* #return
* possible object is
* {#link Boolean }
*
*/
public Boolean isReset() {
return reset;
}
/**
* Sets the value of the reset property.
*
* #param value
* allowed object is
* {#link Boolean }
*
*/
public void setReset(Boolean value) {
this.reset = value;
}
}
Now, is it possible to create an instance of 'GetUserStatus' and add it to the RpcType object via setRpcOperation?
This type of scenario is common:
One schema to represent the message
Multiple schemas to represent the payload.
Below is one way this could be done:
Message Schema - message.xsd
Have one XML schema to represent your message envelope. Introduce one type to represent the body of the message. This type will be extended by the different payloads.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/message"
xmlns="http://www.example.org/message"
elementFormDefault="qualified">
<xsd:element name="message">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="body" type="body"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="body">
</xsd:complexType>
</xsd:schema>
Payload Schema - customer.xsd
This schema corresponds to a specific type of message payload. Notice how the customer type extends the body type from the message schema.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://www.example.org/customer"
xmlns="http://www.example.org/customer"
xmlns:m="http://www.example.org/message"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:import schemaLocation="message.xsd" namespace="http://www.example.org/message"/>
<xsd:complexType name="customer">
<xsd:complexContent>
<xsd:extension base="m:body">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
org.example.message.package-info
This class was generated from message.xsd.
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/message", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.message;
org.example.message.Message
This class was generated from message.xsd.
package org.example.message;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"body"
})
#XmlRootElement(name = "message")
public class Message {
#XmlElement(required = true)
protected Body body;
public Body getBody() {
return body;
}
public void setBody(Body value) {
this.body = value;
}
}
org.example.message.Body
This class was generated from message.xsd.
package org.example.message;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "body")
public class Body {
}
org.example.customer.package-info
This class was generated from customer.xsd.
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.org/customer", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.customer;
org.example.customer.Customer
This class was generated from customer.xsd.
package org.example.customer;
import javax.xml.bind.annotation.*;
import org.example.message.Body;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "customer", propOrder = {
"name"
})
public class Customer extends Body {
#XmlElement(required = true)
protected String name;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
}
Demo Class
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.example.customer.*;
import org.example.message.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Message.class, Customer.class);
Message message = new Message();
Customer customer = new Customer();
customer.setName("Jane Doe");
message.setBody(customer);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(message, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message xmlns="http://www.example.org/message" xmlns:ns2="http://www.example.org/customer">
<body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:customer">
<ns2:name>Jane Doe</ns2:name>
</body>
</message>
EDIT #1
In response to your second question (Cast JAXB2 generated object to JAXBElement?)
I don't see where the JAXBElement comes into play with this example. I am able to run the following code:
import generated.GetFailedLoginCount;
import ietf.params.xml.ns.netconf.base._1.RpcType;
public class Demo {
public static void main(String[] args) {
RpcType rpc = new RpcType();
rpc.setMessageId("123");
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpc.setRpcOperation(rpcOperation);
}
}
EDIT #2
After changing the import to import to http://www.iana.org/assignments/xml-registry/schema/netconf.xsd I'm seeing the same behaviour as you.
To set the property correctly you will need to do something like:
RpcType rpc = new RpcType();
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpcOperation.setReset(true);
JAXBElement<GetFailedLoginCount> rpcOperationJE = new JAXBElement(new QName("foo"), GetFailedLoginCount.class, rpcOperation);
rpc.setRpcOperation(rpcOperationJE);
JAXBElement supplies the element name for the GetFailedLoginCount value. This is required because the element corresponding to the rpcOperation property is substitutable:
<xs:element name="get-config" type="getConfigType" substitutionGroup="rpcOperation" />
In your schema that imports netconf.xsd you should have an element of type "get-failed-login-count" that can be substituted for "rpcOperation". This will be supplied as a QName to the JAXBElement. Since we used element name "foo" above the schema update would look like:
<xs:element name="foo" type="get-failed-login-count" substitutionGroup="rpcOperation" />
Ok, so here is a subset of what I am trying to do. The above example was extremely helpful, but I still am not able to create a JAXBElement:
Base envelope can be found: http://www.iana.org/assignments/xml-registry/schema/netconf.xsd
Payload for rpcOperationType (I added the ** lines):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dmi="http://xml.juniper.net/dmi"
** xmlns:netconf="urn:ietf:params:xml:ns:netconf:base:1.0"
>
**<xs:import schemaLocation="netconf.xsd" namespace="urn:ietf:params:xml:ns:netconf:base:1.0"/>
<!-- get-failed-login-count -->
<xs:complexType name="get-failed-login-count">
**<xs:complexContent>
** <xs:extension base="netconf:rpcOperationType">
<xs:annotation>
<xs:appinfo>
<dmi:rpc-info>
<name>Get failed login count for Authentication failure and Exceeded user</name>
<description>
This command returns the Number of Logins refused due to exceeding allowed limits and Auth failure (24 hour moving window)
</description>
<rpc-reply-tag>failed-login-count</rpc-reply-tag>
</dmi:rpc-info>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="reset" type="xs:boolean" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<dmi:param-info>
<name>Reset Stats</name>
<description>
This will govern the reseting of this statistics data. By default, the data is not reset.
</description>
</dmi:param-info>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
** </xs:extension>
**</xs:complexContent>
</xs:complexType>
Now, the generated GetFailedLogin class extends RpcOperationType, but I am not sure how to set it in the RpcType object:
RpcType rpc = new RpcType();
rpc.setMessageId("123");
GetFailedLoginCount rpcOperation = new GetFailedLoginCount();
rpc.setRpcOperation(); // Expects JAXBElement<? Extends RpcOperationType>

Resources