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.
Related
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.
I am having a problem unmarshalling this class from XML.
The problem is caused by the two elements called 'propertyset'. What actually happens is that the first propertyset is unmarshalled correctly then it is immediately overwritten with the second, if it exists...
Is there any annotation/configuration that I can use to successfully unmarshal this XML?
/**
* <p>Java class for a element declaration.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <element name="a">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element ref="propertyset"/>
* <element ref="propertyset" minOccurs="0"/>
* </sequence>
* <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}long" />
* <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"propertyset",
"systempropertyset"
}, factoryMethod = "createAEx", factoryClass = ObjectFactoryEx.class)
#XmlRootElement(name = "a")
public class A
{
#XmlElement(required = true, type = B.class)
protected B propertyset;
#XmlElement(name = "propertyset", type = B.class)
protected B systempropertyset;
...
}
I have now moved on to using Moxy. With this I can use #XmlPath("propertyset[1]") and #XmlPath("propertyset[2]")
This works as advertised!
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.
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
A very generalized and simplified scenario description:
Application builds JAXB instances through UI,
The JAXB instances are built in different steps are composed in the end,
As this is done, I must perform validation of the JAXB instances created in each step against the XSD to verify that the UI tier does not build nonsense.
Now the schema defines complex types A, B and C. The schema specifies that XML document must have top level element A and this can contain multiple B and this can optionally include C. I create JAXB instance for B and absolutely want to validate this against the complex type definition in the XSD before nesting it under A. However validation of this will fail if I validate against the entire XSD.
Questions: How to validate JAXB instance against only a part of the XSD from which its class has been generated from?
How about using schemagen to generate schema from the JAXB class which instance I want to validate and then validate against that? Do you think that can work? Any other ideas?
I have no previous experience with schemagen and will start prototyping of this solution soon.
Note: in reality, the schemas are not as simple as in the above example and the solution of creating some always-valid mock of A is not feasible option. Not to mention that this kind of validation will be on hundred places to say the least.
create separate schema for element you want to validate, where this element is on root level.
to workaround missing #xmlRoottag see 101 ways to marshal objects with JAXB
Well it turns out that using xsi:type let's one accomplish this.
http://www.w3.org/TR/xmlschema-1/#xsi_type
While working with xjc and schemagen tools please consider same concept which we use in java. In java, every class is a skeleton and object is an instance. Same as we need to consider XSD as skeleton and XML as instance.
xjc tool:- Xsd to Java Class Or Unmarshaling
Consider the below XSD with namespaces for example. The xjc tool will generate the java class along with package-info and object-factory.
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ir="http://irctc.org/service" targetNamespace="http://irctc.org/service">
<xsd:element name="Customer" type="ir:CustomerType"/>
<xsd:complexType name="CustomerType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="src" type="xsd:string"/>
<xsd:element name="dest" type="xsd:string"/>
<xsd:element name="price" type="xsd:float" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Use below command
D:\>xjc Customer.xsd
parsing a schema...
compiling a schema...
org\irctc\service\CustomerType.java
org\irctc\service\ObjectFactory.java
org\irctc\service\package-info.java
Note :- If you have multiple java class then you can use jaxb.index file instead of using ObjectFactory.java.
schemagen tool:- Java Class to Xsd Or Marshaling
Let us suppose we want to generate the Xsd file using java class then first we need to create the ObjectFactory.java Or jaxb.index file and package-info.java in the same package where we have the CustomerType.java.
package org.irctc.service;
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;
#XmlRootElement("Customer")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CustomerType", propOrder = {
"name",
"src",
"dest",
"price"
})
public class CustomerType {
#XmlElement(required = true)
protected String name;
#XmlElement(required = true)
protected String src;
#XmlElement(required = true)
protected String dest;
protected Float price;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getSrc() {
return src;
}
public void setSrc(String value) {
this.src = value;
}
public String getDest() {
return dest;
}
public void setDest(String value) {
this.dest = value;
}
public Float getPrice() {
return price;
}
public void setPrice(Float value) {
this.price = value;
}
}
Use below command
D:\>schemagen org.irctc.service.CustomerType
Note: Writing D:\schema1.xsd
The above command will generate the xsd file. The package of java class will considered as xsd namespaces.
The above details are only for understanding marshaling and unmarshaling process using tools in Jax-B API.
For more details , check below examples
Jax-B Hello World Example
Java-XML mapping with Jax-B 2.0