Discussion:
Tweaking cxf-codegen-plugin Java class generation using binding file – duplicate annotation injected
Arnold Morein
2018-10-17 22:06:06 UTC
Permalink
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>
Daniel Kulp
2018-10-18 13:35:19 UTC
Permalink
I don’t think it’s possible that that would be a valid WSDL. The element tags for the message parts must point to a top level element. It cannot point to a child element of another structure.

Any chance to see the full WSDL as well as the code you are using to try and invoke on the service? I assume you are using the generated stubs. With that schema, the method signature for the method SHOULD be something like:

TLETSMessge doFoo(TLETSMessge msg);

And you’d have to construct the full TLETSMessage object to pass in.

Dan
Post by Arnold Morein
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.
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).
@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;
}


<?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 -->
<annox:annotate>
<annox:annotate
annox:class="javax.xml.bind.annotation.XmlRootElement"
name="Header" />
</annox:annotate>
</bindings>
<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;
}
@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>
--
Daniel Kulp
***@apache.org <mailto:***@apache.org> - http://dankulp.com/blog <http://dankulp.com/blog>
Talend Community Coder - http://talend.com <http://coders.talend.com/>
Loading...