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.
Here is the part of schema that I am using:
<xsd:complexType name="ContentType" mixed="true">
<xsd:annotation>
<xsd:documentation><![CDATA[
The content type is a broad base type allowing any content.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="BaseContentType">
<xsd:sequence>
<xsd:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"
/>
</xsd:sequence>
<xsd:attribute name="orientation" type="OrientationEnum" use="optional"
default="portrait">
<xsd:annotation>
<xsd:documentation><![CDATA[
The #orientation attribute is used to specify a "landscape"
orientation for the published form. This is primarily used
for schedules or for tables.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
And the binding file:
<jxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
version="2.1">
<jxb:bindings schemaLocation="../xsd/USLM-1.0.xsd">
<jxb:bindings
node="//xsd:group[#name='NoteStructure']">
<jxb:property name="NoteStructure3" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
And the xjc command to convert the schema to java objects:
xjc -d out -p test -b binding.xml schema.xsd
But the class generated for ContentType doesn't have class member for any. The generated class is below:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ContentType")
#XmlSeeAlso({
HeadingType.class,
NoteType.class,
QuotedContentType.class,
ColumnType.class,
PType.class
})
public class ContentType
extends BaseContentType
{
#XmlAttribute(name = "orientation")
protected OrientationEnum orientation;
/**
* Gets the value of the orientation property.
*
* #return
* possible object is
* {#link OrientationEnum }
*
*/
public OrientationEnum getOrientation() {
if (orientation == null) {
return OrientationEnum.PORTRAIT;
} else {
return orientation;
}
}
/**
* Sets the value of the orientation property.
*
* #param value
* allowed object is
* {#link OrientationEnum }
*
*/
public void setOrientation(OrientationEnum value) {
this.orientation = value;
}
}
What am I doing wrong?
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.
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.
Is there intelligent way to identify relation between elements using JAXB.
For example: If element SMTP is referred/used in the element Notification and element Configuration
<element name="SMTP">
<complexType>
<sequence>
<element name="fromEmailAddress" type="string"/>
<element name="hostName" type="string"/>
<element name="portNumber" type="string"/>
</sequence>
</complexType>
</element>
<element name="Notification">
<complexType>
<sequence>
<element ref="tns:SMTP"/>
</sequence>
</complexType>
</element>
<element name="Configuration">
<complexType>
<sequence>
<element ref="tns:SMTP"/>
</sequence>
</complexType>
</element>
Is there way to identify this relation/dependancy(SMTP with Notification & Configuration) using JAXB(iam using JAXB to generate classes for the above elements present in my XSD).If it is, sample java code will be helpful
Thanks
Ravi
The Configuration and Notification classes will be generated with an SMTP property:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"smtp"
})
#XmlRootElement(name = "Configuration")
public class Configuration {
#XmlElement(name = "SMTP", namespace = "urn:example", required = true)
protected SMTP smtp;
public SMTP getSMTP() {
return smtp;
}
public void setSMTP(SMTP value) {
this.smtp = value;
}
}
If you are looking to make this a bidirectional relationship you can leverage the #XmlInverseReference extension in EclipseLink JAXB (I'm the tech lead). For more information see:
http://bdoughan.blogspot.com/2010/07/jpa-entities-to-xml-bidirectional.html