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"
></xsd:maxLength>
<xsd:minLength
value="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:minLength
value="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>