CXF Wsdl2java, avec une erreur de type `cannot be unwrapped`...
Par Mathieu CARBONNEAUX
J’essayais de générer un stub java à partir d’un wsdl (utilisation de l’outil wsdl2java) en mode unwrapped avec CXF (l’unwrapping est le mode par défaut de l’outil wsdl2java)… Et je rencontrais l’erreur suivante lors de la génération du java à partir du wsdl :
[java] May 22, 2018 4:59:31 PM org.apache.cxf.wsdl11.WSDLServiceBuilder checkForWrapped
[java] INFO: Operation {http://refservices/MonServiceNS}MonService cannot be unwrapped, input message must reference global element declaration with same localname as operation
J’ai longtemps cherché pour comprendre d’où cela venait…
Le message en question se trouve ici dans le code source de CXF: https://github.com/apache/cxf/blob/master/rt/wsdl/src/main/java/org/apache/cxf/wsdl11/Messages.properties
WRAPPED_RULE_2 = Operation {0} cannot be unwrapped, input message must reference global element declaration with same localname as operation
Il est utilisé ici dans le code source de CXF : https://github.com/apache/cxf/blob/master/rt/wsdl/src/main/java/org/apache/cxf/wsdl11/WSDLServiceBuilder.java
// RULE No.2:
// The input message part refers to à global element declaration whose
// local name is equal to the operation name.
MessagePartInfo inputPart = inputMessage.getMessagePartByIndex(0);
if (!inputPart.isElement()) {
passedRule = false;
} else {
QName inputElementName = inputPart.getElementQName();
inputEl = schemas.getElementByQName(inputElementName);
if (inputEl == null) {
passedRule = false;
} else if (!opInfo.getName().getLocalPart().equals(inputElementName.getLocalPart())) {
passedRule = relaxed;
}
}
if (!passedRule) {
org.apache.cxf.common.i18n.Message message
= new org.apache.cxf.common.i18n.Message("WRAPPED_RULE_2", LOG, opInfo.getName());
LOG.log(logLevel, message.toString());
return;
}
En fait après quelques recherches je me suis rendu compte que c’était lié à la norme Jax-WS, car dans la spécification v2.2 il est écrit la chose suivante (mêmes règles contrôlées dans le code source de CXF) : http://download.oracle.com/otn-pub/jcp/jaxws-2.2-mrel3-evalu-oth-JSpec/jaxws-2_2-mrel3-spec.pdf
**2.3.1.2 Wrapper Style**
à WSDL operation qualifies for wrapper style mapping only if the following criteria are met:
(i) The operation’s input and output messages (if present) each contain only à single part
(ii) The input message part refers to à global element declaration whose localname is equal to the operation name
(iii) The output message (if present) part refers to à global element declaration
(iv) The elements referred to by the input and output message (if present) parts (henceforth referred to as wrapper elements) are both complex types defined using the xsd:sequence compositor
(v) The wrapper elements only contain child elements, they MUST not contain other structures such as wildcards (element or attribute), xsd:choice, substitution groups (element references are not permitted) or attributes; furthermore, they MUST not be nillable.
Donc le générateur de code wsdl2java bloque sur la règle ii…
Au premier abord la règle ii n’est pas évidente à comprendre par elle même … C’est en lisant le code source de CXF que j’ai compris sa signification…
En fait localname fait référence à l’attribut name de l’ element qui définit le type du message d’entrée ( input) de l’ operation…
Avec un exemple c’est plus clair…
L’opération MonService fait référence à un message d’entrée ( input) MonServiceMsg, ce message est composé d’un part (règle i qui indique qu’il faut seulement un seul part dans l’ input pour utiliser le mode unwrapped) fait référence à un type typesns:MonService, et c’est ce type qui doit avoir le même nom que l’opération, là en l’occurrence MonService.
Donc le name de l’élément <xsd:element name="MonService"> doit être le même que le name de l’ operation <operation name="MonService">.
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://MonService.com"
xmlns:typesns="http://MonService.com/types/"
targetNamespace="http://MonService.com">
<types>
<xsd:schema targetNamespace="http://arcadye.sfr.com/types/"
xmlns="http://arcadye.sfr.com/types/"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xsd:element name="MonService">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="args1" type="xsd:string"/>
<xsd:element name="args2" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
…
<message name="MonServiceMsg">
<part element="typesns:MonService" name="MonService"/>
</message>
…
<portType name="ArcadyeDematService">
<operation name="MonService">
<input message="tns:MonServiceMsg"/>
<output message="tns:MonServiceResponseMsg"/>
</operation>
</portType>
…
