Particularidades de Java2WSDL en Axis
Hace un par de semana me estuve peleando con los scripts de Axis que permiten crear documento WSDL a partir de una clase Java, Java2WSDL y viceversa, generar el skeleton o stub Java a partir de un documento WSDL, WSDL2Java. Particularmente la herramienta java2wsdl tiene ciertos detalles que pueden llegar a ser molestos si no se sabe como abordarlos. A continuación os cuento los problemas que tuve y las soluciones que adopté.
1. WSDL es un estándar web.
La afirmación anterior implica que la información que puede contener este documento debe ser independiente de cualquier plataforma, arquitectura, sistema operativo o lenguaje de programación, por tanto, en la sección donde se define los tipos no puede haber referencia a ningún tipo específico Java, tal como List, ArrayList, Map, ….
Solución:
Cualquier método que quiera ser publicado a través de un servicio web debe tener como parámetros de entrada y/o salida, tipos estándares, esto es en Java, tipos primitivos, arrays u objetos propios serializables que contengan tipos estándares.
Ejemplo
Supongamos que tenemos una clase Foo que queremos publicar como servicio web y que contiene un tipo no estándar, por ejemplo una Lista.
public class Foo {
private List<String> lstStrings;
public List<String> getLstStrings() {
return this.lstStrings;
}
public void setLstStrings(List<String> lstStrings){
this.lstStrings = lstStrings;
}
...
}
Bien, pues si queremos que la herramienta java2wsdl genere un documento WSDL correcto debemos transformar el código anterior en el siguiente:
public class Foo {
private List<String> lstStrings;
private String[] arrayStrings; // Según la versión de axis, es necesario declararlo o no
public List<String> getLstStrings() {
return this.lstStrings;
}
public void setLstStrings(List<String> lstStrings) {
this.lstStrings = lstStrings;
}
public String[] getArrayStrings() {
if ( getLstStrings() != null ) {
return getLstStrings().toArray(new String[getLstStrings().size()]);
}
return new String[0];
}
public void setArrayStrings(String[] arrayStrings) {
this.setArrayStrings(Arrays.asList(arrayStrings));
}
...
}
2. No están soportados los modelos de datos con clases internas.
Actualmente el script no genera correctamente el conjunto de tipos del documento WSDL si el método de la clase a publicar contiene parametros cuyos tipos sean clases internas.
Este error es debido a un fallo en el jar annogen-0.1.0; existe un parche oficioso que genera el WSDL correctamente pero si usamos wsdl2java para generar el cliente, la invocación al servicio dará un fallo.
Solución:
- Sacar las clases internas de la clase del servicio.
- Utilizar el jar oficioso de Deepal Jayasinghe y crear el stub sin utilizar WSDL2Java.
3. Nuestro servicio lanza una excepción.
Siempre que nuestro servicio lanza una Exception la herramienta java2wsdl intenta mapear el tipo de la excepción a un tipo WSDL. Esto siempre produce el código :
...
<xs:complexType name="MyException">
<xs:complexContent>
<xs:extension base="xs:Exception" />
<!-- o <xs:extension base="xs:RuntimeException" /> -->
<xs:sequence />
</xs:complexContent>
</xs:complexType>
...
Al final java2wsdl busca la clase padre de la que extiende nuestra exception para mapearla según la semántica que permite WSDL, sin embargo, ni xs:Exception ni xs:RuntimeException existen como tipo estándares de XML-Schema lo que provoca la existerncia de warnings/errores de los editores XML que validan los documentos.
Solución: La única solución que he encontrado es hacer el siguiente cambio :
…
<xs:complexType name="MyException">
<xs:complexContent>
<xs:extension base="xs:anyType" />
<!– o <xs:extension base="xs:anyType" /> –>
<xs:sequence />
</xs:complexContent>
</xs:complexType>
…
Eso si, si se genera un cliente a partir de este documento WSDL se deberán modificar las clases asociadas a las excepciones para que extiendan de RuntimeException o Exception o cualquier otra.
4. <soap12:fault />.
Cuando se crea un documento WSDL para que pueda ser utilizado por las dos versiones de SOAP existentes, 1.1 y 1.2, la parte del binding de SOAP 1.2 es incorrecta.
La herramienta java2wsdl genera un código tal como este :
...
<wsdl:binding...>
<soap12:opertation ... />
<wsdl:operation ...>
...
<wsdl:fault ...>
<soap12:fault use="literal" name="MyException" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
...
pues el código anterior falla, el elemento <soap12:fault use="literal" name="MyException" /> no es correcto y, por ejemplo, la herramient wsdl2java no puede crear un cliente correcto a partir del WSDL
Solución:
Cambiar <soap12:fault use="literal" name="MyException" /> por <soap:fault use="literal" name="MyException" />
Si habéis tenido problemas parecidos y los habéis resuelto de una forma distinta a la mía, por favor, no dudéís es compartirlo para que todos salgamos ganando.

