Arnold Morein
2018-10-17 22:06:06 UTC
CXF: 3.1.10
JDK 1.8
Tomcat 8.0.18
I have a situation with a WSDL that is very terse and the resultant stubs, though they compile in the WSDLâs JAR project, cannot be used in the main applicationâs WAR project.
The WSDLâs single message structure is like this:
Message
----(2 string attributes)
--Header
----(4 string attributes)
--Body
----(sequence)
------Request
--------(xsd:any)
------Response
--------(xsd:any)
The first problem was that the classes werenât serializable. So I started building a binding file to add that aspect. That part was easy.
But the Header, Body, Response, and Request classes are generated as internal static sub-classes of Message (because in the WSDL schema section, they are all internal to the Message).
When CXF tries to marshal a call to the service, an exception occurs saying:
org.apache.cxf.interceptor.Fault: Marshalling Error: unable to marshal type "a.b.Message$Header" as an element because it is missing an @XmlRootElement annotation
The Message class has an @XmlRootElement annotation, but not the subclasses. The class looks like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"content"
})
@XmlRootElement(name = "TLETSMessage")
public class TLETSMessage
implements Serializable
{
private final static long serialVersionUID = 1L;
@XmlElementRefs({
@XmlElementRef(name = "Header", type = JAXBElement.class),
@XmlElementRef(name = "Body", type = JAXBElement.class)
})
@XmlMixed
protected List<Serializable> content;
@XmlAttribute(name = "key", required = true)
protected String key;
@XmlAttribute(name = "version", required = true)
protected String version;
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
âŠ
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"request",
"response"
})
public static class Body
implements Serializable
{
private final static long serialVersionUID = 1L;
@XmlElement(name = "Request", required = true)
protected TLETSMessage.Body.Request request;
@XmlElement(name = "Response")
protected TLETSMessage.Body.Response response;
public TLETSMessage.Body.Request getRequest() {
return request;
}
public void setRequest(TLETSMessage.Body.Request value) {
this.request = value;
}
public TLETSMessage.Body.Response getResponse() {
return response;
}
âŠ
I then added entries to the binding file and pom.xml to add the @XmlRootElement annotation to the Header and Body classes:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb <http://java.sun.com/xml/ns/jaxb>"
xmlns:annox="http://annox.dev.java.net <http://annox.dev.java.net/>" extensionBindingPrefixes="xjc annox"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc <http://java.sun.com/xml/ns/jaxb/xjc>"
xmlns:xsd="http://www.w3.org/2001/XMLSchema <http://www.w3.org/2001/XMLSchema>"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/ <http://schemas.xmlsoap.org/wsdl/>" version="2.1"
<globalBindings>
<serializable uid="1" />
</globalBindings>
<bindings schemaLocation="META-INF/DMVService.wsdl#types1"
node="/xsd:schema"
<!-- Annotate the following classes with XmlRootElement -->
<bindings node="//xsd:element[@name='Header']">
<annox:annotate>
<annox:annotate
annox:class="javax.xml.bind.annotation.XmlRootElement"
name="Header" />
</annox:annotate>
</bindings>
<bindings node="//xsd:element[@name='Body']">
<annox:annotate>
<annox:annotate
annox:class="javax.xml.bind.annotation.XmlRootElement"
name="Body" />
</annox:annotate>
</bindings>
</bindings>
</bindings>
And I thought I had it done, but what is generated is wrong, the annotation is put on a method that isnât explicit in the WSDL so I guess a generic one was generated.
@XmlRootElement(name = "Body")
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
But not where I hoped it would be:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"request",
"response"
})
public static class Body
implements Serializable
{
Here is an extract from the WSDL, hopefully someone can tell me how to fix the binding?
<wsdl:types>
<xsd:schema xmlns="http://www.openfox.com <http://www.openfox.com/>"
targetNamespace="http://www.openfox.com <http://www.openfox.com/>"
<!-- TLETSMessage -->
<xsd:element name="TLETSMessage">
<xsd:complexType mixed="true">
<xsd:sequence>
<!-- Header -->
<xsd:element name="Header">
<xsd:complexType>
<xsd:sequence>
<!-- Initiator -->
<xsd:element name="Initiator">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:maxLength
value="9"
value="4"
</xsd:simpleType>
</xsd:element>
<!-- Destination -->
<xsd:element name="Destination">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:maxLength
value="9"
value="2"
</xsd:simpleType>
</xsd:element>
<!-- ControlField -->
<xsd:element name="ControlField">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<!--xsd:pattern value="\d{6}"/-->
<xsd:length
value="10"
</xsd:simpleType>
</xsd:element>
<!-- UserId -->
<xsd:element name="UserId">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:length value="7"></xsd:length>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element> <!-- end Header -->
<!-- Body -->
<xsd:element name="Body">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request">
<xsd:complexType>
<xsd:sequence>
<xsd:any></xsd:any>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Response"
minOccurs="0" maxOccurs="1"
<xsd:complexType>
<xsd:sequence>
<xsd:any></xsd:any>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<!-- TLETSMessage attributes -->
<xsd:attribute name="key" type="xsd:string"
use="required"
type="xsd:string" use="required"
</xsd:element> <!-- end TLETSMessage -->
</xsd:schema>
JDK 1.8
Tomcat 8.0.18
I have a situation with a WSDL that is very terse and the resultant stubs, though they compile in the WSDLâs JAR project, cannot be used in the main applicationâs WAR project.
The WSDLâs single message structure is like this:
Message
----(2 string attributes)
--Header
----(4 string attributes)
--Body
----(sequence)
------Request
--------(xsd:any)
------Response
--------(xsd:any)
The first problem was that the classes werenât serializable. So I started building a binding file to add that aspect. That part was easy.
But the Header, Body, Response, and Request classes are generated as internal static sub-classes of Message (because in the WSDL schema section, they are all internal to the Message).
When CXF tries to marshal a call to the service, an exception occurs saying:
org.apache.cxf.interceptor.Fault: Marshalling Error: unable to marshal type "a.b.Message$Header" as an element because it is missing an @XmlRootElement annotation
The Message class has an @XmlRootElement annotation, but not the subclasses. The class looks like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"content"
})
@XmlRootElement(name = "TLETSMessage")
public class TLETSMessage
implements Serializable
{
private final static long serialVersionUID = 1L;
@XmlElementRefs({
@XmlElementRef(name = "Header", type = JAXBElement.class),
@XmlElementRef(name = "Body", type = JAXBElement.class)
})
@XmlMixed
protected List<Serializable> content;
@XmlAttribute(name = "key", required = true)
protected String key;
@XmlAttribute(name = "version", required = true)
protected String version;
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
âŠ
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"request",
"response"
})
public static class Body
implements Serializable
{
private final static long serialVersionUID = 1L;
@XmlElement(name = "Request", required = true)
protected TLETSMessage.Body.Request request;
@XmlElement(name = "Response")
protected TLETSMessage.Body.Response response;
public TLETSMessage.Body.Request getRequest() {
return request;
}
public void setRequest(TLETSMessage.Body.Request value) {
this.request = value;
}
public TLETSMessage.Body.Response getResponse() {
return response;
}
âŠ
I then added entries to the binding file and pom.xml to add the @XmlRootElement annotation to the Header and Body classes:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb <http://java.sun.com/xml/ns/jaxb>"
xmlns:annox="http://annox.dev.java.net <http://annox.dev.java.net/>" extensionBindingPrefixes="xjc annox"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc <http://java.sun.com/xml/ns/jaxb/xjc>"
xmlns:xsd="http://www.w3.org/2001/XMLSchema <http://www.w3.org/2001/XMLSchema>"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/ <http://schemas.xmlsoap.org/wsdl/>" version="2.1"
<globalBindings>
<serializable uid="1" />
</globalBindings>
<bindings schemaLocation="META-INF/DMVService.wsdl#types1"
node="/xsd:schema"
<!-- Annotate the following classes with XmlRootElement -->
<bindings node="//xsd:element[@name='Header']">
<annox:annotate>
<annox:annotate
annox:class="javax.xml.bind.annotation.XmlRootElement"
name="Header" />
</annox:annotate>
</bindings>
<bindings node="//xsd:element[@name='Body']">
<annox:annotate>
<annox:annotate
annox:class="javax.xml.bind.annotation.XmlRootElement"
name="Body" />
</annox:annotate>
</bindings>
</bindings>
</bindings>
And I thought I had it done, but what is generated is wrong, the annotation is put on a method that isnât explicit in the WSDL so I guess a generic one was generated.
@XmlRootElement(name = "Body")
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
But not where I hoped it would be:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"request",
"response"
})
public static class Body
implements Serializable
{
Here is an extract from the WSDL, hopefully someone can tell me how to fix the binding?
<wsdl:types>
<xsd:schema xmlns="http://www.openfox.com <http://www.openfox.com/>"
targetNamespace="http://www.openfox.com <http://www.openfox.com/>"
<!-- TLETSMessage -->
<xsd:element name="TLETSMessage">
<xsd:complexType mixed="true">
<xsd:sequence>
<!-- Header -->
<xsd:element name="Header">
<xsd:complexType>
<xsd:sequence>
<!-- Initiator -->
<xsd:element name="Initiator">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:maxLength
value="9"
</xsd:maxLength>
<xsd:minLengthvalue="4"
</xsd:minLength>
</xsd:restriction></xsd:simpleType>
</xsd:element>
<!-- Destination -->
<xsd:element name="Destination">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:maxLength
value="9"
</xsd:maxLength>
<xsd:minLengthvalue="2"
</xsd:minLength>
</xsd:restriction></xsd:simpleType>
</xsd:element>
<!-- ControlField -->
<xsd:element name="ControlField">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<!--xsd:pattern value="\d{6}"/-->
<xsd:length
value="10"
</xsd:length>
</xsd:restriction></xsd:simpleType>
</xsd:element>
<!-- UserId -->
<xsd:element name="UserId">
<xsd:simpleType>
<xsd:restriction
base="xsd:string"
<xsd:length value="7"></xsd:length>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element> <!-- end Header -->
<!-- Body -->
<xsd:element name="Body">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request">
<xsd:complexType>
<xsd:sequence>
<xsd:any></xsd:any>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Response"
minOccurs="0" maxOccurs="1"
<xsd:complexType>
<xsd:sequence>
<xsd:any></xsd:any>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<!-- TLETSMessage attributes -->
<xsd:attribute name="key" type="xsd:string"
use="required"
</xsd:attribute>
<xsd:attribute name="version"type="xsd:string" use="required"
</xsd:attribute>
</xsd:complexType></xsd:element> <!-- end TLETSMessage -->
</xsd:schema>