Al final de este articulo se encuentran dos ejemplos de como utilizar las clases generadas por el Axis2 Code Generator plugin para Eclipse. Primero discuto algunos errores que encontre en su uso.
Oh San Google, San Google como fallas!
Esta es una de esas veces donde me quise arrancar los pelos buscando como solucionar dos errores horripilosos de Axis2 cuando se genera Web clients.
Error 1:
org.apache.axis2.Axis Fault: org.apache.axis2.Databinding.ADBException: Unexpected subelement .....
En este primer error, San Google fue mas o menos de ayuda. Digo mas o menos porque lo unico que hizo fue confirmar que hay un bug en la generacion de clases con el Axis2 con Databinding ADB. Lo que sucede en este error (segun lo que lei) es que el ADB esta esperando que el xml request o response (debes encontrar en cual de los dos o si en los dos esta el error) envie un orden especifico "a,b,c" y el webservice esta retornando un orden "a,d,c" por ende, el Unexpected Subelement. No comprendi a cabalidad si el error es porque el orden del schema en el wsdl no corresponde, el bug es del ADB. Creo que lo mas correcto seria corregir el wsdl en el webservice, pero como en este caso nosotros solo consumiamos el webservice y no lo creamos, asi que no pudimos darnos el lujo de corregirlo.
Ya he utilizado el ADB databing antes y no me genero este error. Es el databing por default del Axis2 Code Generator y su codigo es mas sencillo. (abajo un ejemplo).
Solucion: Asumo yo que se considera bug del ADB porque no deberia quejarse y solo recibir lo que se le envia. Por eso, la recomendacion general de San Google fue utilizar xmlbeans de Databinding.
Generamos nuevamente el codigo del cliente con el Axis2 Code Generator con databinding xmlbeans y todo parecia ir bien hasta que aparecio este error:
Error2:
ClassNotFoundException : Cannot load SchemaTypeSystem. Unable to load class with name schemaorg_apache_xmlbeans.system...
.TypeSystemHolder.
Make sure the generated binary files are on the classpath.
Todo San Google tenia la misma solucion: asegurate de agregar la clase TypeSystemHolder.class al classpath. Muy pocos decian como (porque agregar algo al classpath es lo mas sencillo del mundo, pero no para esto!). No intentes agregar la clase al classpath en ningun lado, no funciona. Una cosa que me enoja de los ejemplos y ayuditas del Axis2 es que todos son para Web dynamic projects! U_U...
Algunos mencionaban soluciones utilizando un WSDL2JAVA code generator (que en esencia es lo mismo que el Axis2 Code Generator) y utilizar un ANT script para copiar la disque clase al classpath. Lo triste es que todos decian: "copialo al build/classes" y los JAVA projects (que son los que generalmente uso para los webclients) no tienen esas carpetas!!! ¬_¬
Solucion sencillisima: click en build path ------> configure build path. En la pestaña de Source--->click en Add Folder----->agrega la carpeta resources que te creo el Axis2 que contiene el TypeSystemHolder.class y un monton de otras cosas mas. Agrega toda la carpeta, no agregues solo la subcarpeta con la clase. NO es necesario ningun xmlbeans.jar; que no te engañe Google!!!
Aqui los ejemplos (Son solo una idea o guia);
ADB Databing.
Como menciones arriba, es el default y el mas "amigable" de usar.
ExampleServiceStub service=null; // Declara el servicestub primero
ExampleParameter param= new ExampleParameter(); //averigua que tipo de parametro espera el metodo que desea consumir.
param.setA("A");
param.setB("B");
param.setC("C"); //....etc
ExampleMethod method = new ExampleMethod(); //llena el parametro del metodo
method.setFunctionCall(param);
service = _servicePool.borrowService(_endPoint, _repositoryPath, _userName);
ExampleResponse functionresponse = service.function(method); //invoca la funcion
ExampleResponse response = functionresponse.getResponseMessage();
XmlBeans
Jamas imagine que el codigo de xmlbeans seria tan diferente. No es en si MUY diferente, pero sin una guia, definitivamente seria un reto.
ExampleStub service = null;
service = _servicePool.borrowService(_endPoint, _repositoryPath, _userName, _timeOut);
ExampleRequestDocument request = ExampleRequestDocument.Factory.newInstance(); //no utilices la palabra new aqui. Se instancia con un Factory.newInstance();
ExampleParameterQuery param = request.addNewExampleRequest();
param.setA("A");
param.setB("B");
param.setC("C"); //...etc
request.setParameter(param);
ExampleResponseDocument response = service.getFunction(request);
Si esto te ayuda, me alegro mucho! A esta mente pollo que todo se le olvida le servira mucho!
Oh San Google, San Google como fallas!
Esta es una de esas veces donde me quise arrancar los pelos buscando como solucionar dos errores horripilosos de Axis2 cuando se genera Web clients.
Error 1:
org.apache.axis2.Axis Fault: org.apache.axis2.Databinding.ADBException: Unexpected subelement .....
En este primer error, San Google fue mas o menos de ayuda. Digo mas o menos porque lo unico que hizo fue confirmar que hay un bug en la generacion de clases con el Axis2 con Databinding ADB. Lo que sucede en este error (segun lo que lei) es que el ADB esta esperando que el xml request o response (debes encontrar en cual de los dos o si en los dos esta el error) envie un orden especifico "a,b,c" y el webservice esta retornando un orden "a,d,c" por ende, el Unexpected Subelement. No comprendi a cabalidad si el error es porque el orden del schema en el wsdl no corresponde, el bug es del ADB. Creo que lo mas correcto seria corregir el wsdl en el webservice, pero como en este caso nosotros solo consumiamos el webservice y no lo creamos, asi que no pudimos darnos el lujo de corregirlo.
Ya he utilizado el ADB databing antes y no me genero este error. Es el databing por default del Axis2 Code Generator y su codigo es mas sencillo. (abajo un ejemplo).
Solucion: Asumo yo que se considera bug del ADB porque no deberia quejarse y solo recibir lo que se le envia. Por eso, la recomendacion general de San Google fue utilizar xmlbeans de Databinding.
Generamos nuevamente el codigo del cliente con el Axis2 Code Generator con databinding xmlbeans y todo parecia ir bien hasta que aparecio este error:
Error2:
ClassNotFoundException : Cannot load SchemaTypeSystem. Unable to load class with name schemaorg_apache_xmlbeans.system...
.TypeSystemHolder.
Make sure the generated binary files are on the classpath.
Todo San Google tenia la misma solucion: asegurate de agregar la clase TypeSystemHolder.class al classpath. Muy pocos decian como (porque agregar algo al classpath es lo mas sencillo del mundo, pero no para esto!). No intentes agregar la clase al classpath en ningun lado, no funciona. Una cosa que me enoja de los ejemplos y ayuditas del Axis2 es que todos son para Web dynamic projects! U_U...
Algunos mencionaban soluciones utilizando un WSDL2JAVA code generator (que en esencia es lo mismo que el Axis2 Code Generator) y utilizar un ANT script para copiar la disque clase al classpath. Lo triste es que todos decian: "copialo al build/classes" y los JAVA projects (que son los que generalmente uso para los webclients) no tienen esas carpetas!!! ¬_¬
Solucion sencillisima: click en build path ------> configure build path. En la pestaña de Source--->click en Add Folder----->agrega la carpeta resources que te creo el Axis2 que contiene el TypeSystemHolder.class y un monton de otras cosas mas. Agrega toda la carpeta, no agregues solo la subcarpeta con la clase. NO es necesario ningun xmlbeans.jar; que no te engañe Google!!!
Aqui los ejemplos (Son solo una idea o guia);
ADB Databing.
Como menciones arriba, es el default y el mas "amigable" de usar.
ExampleServiceStub service=null; // Declara el servicestub primero
ExampleParameter param= new ExampleParameter(); //averigua que tipo de parametro espera el metodo que desea consumir.
param.setA("A");
param.setB("B");
param.setC("C"); //....etc
ExampleMethod method = new ExampleMethod(); //llena el parametro del metodo
method.setFunctionCall(param);
service = _servicePool.borrowService(_endPoint, _repositoryPath, _userName);
ExampleResponse functionresponse = service.function(method); //invoca la funcion
ExampleResponse response = functionresponse.getResponseMessage();
XmlBeans
Jamas imagine que el codigo de xmlbeans seria tan diferente. No es en si MUY diferente, pero sin una guia, definitivamente seria un reto.
ExampleStub service = null;
service = _servicePool.borrowService(_endPoint, _repositoryPath, _userName, _timeOut);
ExampleRequestDocument request = ExampleRequestDocument.Factory.newInstance(); //no utilices la palabra new aqui. Se instancia con un Factory.newInstance();
ExampleParameterQuery param = request.addNewExampleRequest();
param.setA("A");
param.setB("B");
param.setC("C"); //...etc
request.setParameter(param);
ExampleResponseDocument response = service.getFunction(request);
Si esto te ayuda, me alegro mucho! A esta mente pollo que todo se le olvida le servira mucho!
Muchas gracias Linda, muy clara tu explicación
ReplyDelete