services que jax from entendiendo ejemplo crear wsdl jar jax-ws wsimport

wsdl - que - soap web services java



JAX-WS Cargando WSDL desde jar (13)

Aquí está mi solución alternativa.

Desempaqueto el WSDL del jar y lo escribo en un archivo cerca del jar:

File wsdl = new File("../lib/service.wsdl"); InputStream source = getClass().getResource("resources/service.wsdl").openStream(); FileOutputStream out = new FileOutputStream(wsdl); byte[] buffer = new byte[512]; int read; while((read = source.read(buffer)) >= 0) { out.write(buffer, 0, read); }

Luego apunte las clases de servicio a file:../lib/service.wsdl .

Esto funciona, pero apreciaría si alguien me pudiera mostrar una solución más elegante.

Estoy escribiendo un cliente gordo que utiliza un servicio SOAP para algunas funciones (informe de errores, etc.)

Tengo JAX-WS funcionando bien, pero de forma predeterminada (al menos en netbeans) recupera el WSDL del servidor remoto cada vez que se inicializa el servicio. Espero que esto ayude a proporcionar algún soporte de versionado, etc., pero no es lo que quiero.

He agregado el wsdllocation a wsimport para apuntar las clases generadas a un recurso local. El siguiente fragmento es el URL que se carga para el recurso WSDL de ApplicationService.java.

baseUrl = net.example.ApplicationService.class.getResource("."); url = new URL(baseUrl, "service.wsdl");

Estoy bastante seguro de que no debería tener problemas para apuntar a un recurso almacenado dentro de un contenedor en el paquete net / example / resources, y el propio jar se construye como se espera. Sin embargo, el servicio no se cargará ... específicamente, recibo una NullPointerException cuando llamo ApplicationService.getPort ();

es posible? ¿O simplemente una caza de ganso salvaje?


Aquí hay uno que funciona para mí (en particular, a través de http y https ). Caso de JAX-WS de Oracle JDK 1.8.0_51 trabajando con clases creadas por Apache CXF 3.1.1.

Tenga en cuenta que el WSDL remoto se obtiene solo en la primera invocación en cualquier caso. Dependiendo del patrón de uso (programa de larga duración), esto puede ser completamente aceptable.

Los basicos:

  • Descargue el WSDL del host remoto y almacénelo como archivo: wget --output-document=wsdl_raw.xml $WSDL_URL
  • Es posible que desee xmllint --format wsdl_raw.xml > wsdl.xml para un buen formato
  • Genere clases de clientes usando la herramienta de línea de comandos : ./cxf/bin/wsdl2java -d output/ -client -validate wsdl.xml e importe en su proyecto

Verifique que las definiciones de servicio para http y https existan en el archivo WSDL. En mi caso, el proveedor no tenía uno para https (pero aceptó el tráfico de https ) y tuve que agregarlo manualmente. Algo a lo largo de estas líneas debería estar en el WSDL:

<wsdl:service name="fooservice"> <wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort"> <soap:address location="http://ws.example.com/a/b/FooBarWebService"/> </wsdl:port> </wsdl:service> <wsdl:service name="fooservice-secured"> <wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort"> <soap:address location="https://ws.example.com/a/b/FooBarWebService"/> </wsdl:port> </wsdl:service>

CXF debería haber generado una clase que implemente javax.xml.ws.Service llamado por ejemplo Fooservice , con los constructores apropiados:

public class Fooservice extends Service { public Fooservice(URL wsdlLocation) { super(wsdlLocation, SERVICE); } public Fooservice(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public Fooservice() { super(WSDL_LOCATION, SERVICE); } ...etc...

En algún lugar de su código (aquí, algunos Groovy para facilitar la lectura), inicializa la instancia de Service anterior y luego invoca un puerto. Aquí, dependiendo de la bandera llamada secure , usamos https o http :

static final String NAMESPACE = ''com.example.ws.a.b'' static final QName SERVICE_NAME_HTTP = new QName(NAMESPACE, ''fooservice'') static final QName SERVICE_NAME_HTTPS = new QName(NAMESPACE, ''fooservice-secured'') Fooservice wsService File wsdlfile = new File(''/somewhere/on/disk/wsdl.xml'') // If the file is missing there will be an exception at connect // time from sun.net.www.protocol.file.FileURLConnection.connect // It should be possible to denote a resource on the classpath // instead of a file-on-disk. Not sure how, maybe by adding a handler // for a ''resource:'' URL scheme? URI wsdlLocationUri = java.nio.file.Paths(wsdlfile.getCanonicalPath()).toUri() if (secure) { wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTPS) } else { wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP) } SomeServicePort port = wsService.getSomeServicePort() port.doStuff()

La alternativa, que descarga el WSDL en una conexión que es independiente de la conexión utilizada para la invocación del servicio (use tcpdump -n -nn -s0 -A -i eth0 ''tcp port 80'' para observar el tráfico) es simplemente hacer:

URI wsdlLocationUri if (secure) { wsdlLocationUri = new URI(''https://ws.example.com/a/b/FooBarWebService?wsdl'') } else { wsdlLocationUri = new URI(''http://ws.example.com/a/b/FooBarWebService?wsdl'') } Fooservice wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP) SomeServicePort port = wsService.getSomeServicePort() port.doStuff()

Tenga en cuenta que esto realmente usa https si el wsdlLocationUri especifica https , a pesar del hecho de que el wsService se ha inicializado con SERVICE_NAME_HTTP . (No estoy seguro de por qué: ¿el servicio utiliza el esquema empleado para recuperar el recurso WSDL?)

Y eso es todo.

Para depurar la conexión, pase:

-Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true -Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=true

a la JVM en la línea de comando. Esto escribirá la información del código de conexión http en stdout (desafortunadamente NO en java.util.logging . ¡Oracle, por favor!).


Aunque puede hacer que funcione con algunas manipulaciones, recomendaría no hacerlo y mantenerlo como lo tiene ahora.

Los proveedores de servicios finales de servicios web deben proporcionar un WSDL como parte de su contrato. El código que genere debe ser extraído del WSDL desde el propio servidor.

En la implementación en WebSphere, puede cambiar los puntos finales a otros puntos finales desde la interfaz de usuario de la implementación. Es posible que otros servidores de aplicaciones necesiten encontrar el XML de enlace específico del proveedor para hacerlo.

Solo ocurre en la inicialización, por lo que el impacto en su aplicación general debe ser insignificante.



Me encontré con el mismo tema. El código de cliente de JAXWS genera el MyService.class.getResource(".") Para cargar el archivo wsdl ... pero después de probar esto solo parece funcionar si el archivo de clase está en un directorio en el archivo filestem. Si el archivo de clase está en un JAR, esta llamada devuelve un valor nulo para la URL.

Suena como un error en el JDK ya que si construyes tu URL de esta manera:

final URL url = new URL( MyService.class.getResource( MyService.class.getSimpleName() + ".class"), "myservice.wsdl");

entonces también funciona si la clase y wsdl están agrupados en un tarro.

¡Supongo que la mayoría de la gente en realidad se envuelve en un frasco!


Mi solución fue modificar el servicio generado. Debe cambiar wsdlLocation en la anotación del encabezado y el bloque de creación de instancias se verá así:

static { URL url = null; url = com.ups.wsdl.xoltws.ship.v1.ShipService.class.getResource("Ship.wsdl"); SHIPSERVICE_WSDL_LOCATION = url; }

Coloco el archivo wsdl en el directorio bin al lado de la clase ShipService


No hay necesidad de complicar nada, solo usa jar classloader

ClassLoader cl = SomeServiceImplService.class.getClassLoader(); SERVICE_WSDL_LOCATION = cl.getResource("META-INF/wsdls/service.wsdl");

¡Intentalo!


Otra respuesta es usar el

new Service(wsdllocation, servicename );

para obtener el objeto de servicio.

Así es como resolví el problema.


Por lo menos para el reciente JAX-WS, no necesita realizar ningún catálogo de esquemas ni la configuración de ubicación wsdl programática SI coloca el WSDL en el JAR y luego establece wsimport wsdlLocation en la ruta de recursos relativa del WSDL en el JAR. Eso es, JAX-WS utiliza el Class.getResource incorporado de Class.getResource para cargar el WSDL.

Si estás usando Maven es algo como:

<plugin> <groupId>org.jvnet.jax-ws-commons</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <goals> <goal>wsimport</goal> </goals> <!-- Following configuration will invoke wsimport once for each wsdl. --> <configuration> <!--- VERY IMPORTANT THAT THE PATH START WITH ''/'' --> <wsdlLocation>/com/adamgent/ws/blah.wsdl</wsdlLocation> <wsdlDirectory>${basedir}/src/main/resources/com/adamgent/ws</wsdlDirectory> <wsdlFiles><wsdlFile>blah.wsdl</wsdlFile></wsdlFiles> </configuration> </execution> </executions> </plugin>

Para el ejemplo anterior, por lo tanto, pondría el WSDL utilizando el diseño del proyecto Maven aquí src/main/resources/com/adamgent/ws .

Asegúrese de que el WSDL entre en el JAR para Maven como:

<build> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> ....

Ahora su código generado por wsimport y WSDL están en un JAR autónomo. Para utilizar el servicio, no tiene que configurar la ubicación WSDL y es tan fácil como:

BlahService myService = new BlayService_Service().getBlahServicePort();

Debería ser trivial asignar esto a wsimport de ANT.


Reemplacé la ubicación WSDL antes de construir el contenedor del cliente aquí.

  1. Copie los WSDL a las clases dir.
  2. Reemplace la clase de servicio refiérase a WSDL usando classpath.
  3. construir los apéndices del cliente.
  4. tarro de los talones.

<copy todir="@{dest-dir}/@{dir-package}" verbose="@{verbose}"> <fileset dir="@{dir-wsdl}" includes="*.wsdl,*.xsd" /> </copy> <echo message="Replacing Service to point to correct WSDL path..." /> <replaceregexp match="new URL(.*)" replace=''Class.class.getResource("@{name-wsdl}");'' flags="gm"> <fileset dir="@{source-dest-dir}"> <include name="@{dir-package}/*Service.java" /> </fileset> </replaceregexp> <replaceregexp match="catch (.*)" replace=''catch (Exception ex) {'' flags="gm"> <fileset dir="@{source-dest-dir}"> <include name="@{dir-package}/*Service.java" /> </fileset> </replaceregexp>


Sí, esto es definitivamente posible, ya que lo he hecho al crear clientes a través de javax.xml.ws.EndpointReference, una clase relacionada con WS-A. He agregado una referencia de ruta de clase al WSDL a la referencia de punto final de WS-A y la implementación de Metro de JAX-WS lo cargó bien. Ya sea que esté cargando el WSDL desde la EndPointReference WS-A o desde un archivo o una URL http, su implementación JAX-WS debe usar el mismo código de análisis WSDL que todo lo que está haciendo para resolver las URL.

El mejor enfoque para usted es probablemente hacer algo como lo siguiente:

URL wsdlUrl = MyClass.class.getResource( "/class/path/to/wsdl/yourWSDL.wsdl"); Service yourService= Service.create( wsdlUrl, ...);

Donde ... representa el QName de un servicio WSDL dentro de su WSDL. Ahora lo importante a recordar es que su WSDL debe ser completo y válido. Esto significa que si su WSDL importa archivos XSD u otros WSDL, las URL deben ser correctas. Si incluyó su WSDL y XSD importados en el mismo JAR que el archivo WSDL, debe usar las URL relativas para las importaciones y mantener todas sus importaciones en el mismo archivo JAR. El controlador de URL de JAR no trata las direcciones URL relativas como relativas con respecto a la ruta de clase, sino más bien en relación con el archivo JAR, por lo que no puede tener importaciones en su WSDL que se ejecutan a través de archivos JAR a menos que implemente un controlador de URL personalizado y su propio prefijo. Resolución basada en classpath de las importaciones. Si su WSDL importa recursos externos, está bien, pero se está inscribiendo para problemas de mantenimiento si esos recursos alguna vez se mueven. Incluso el uso de una copia estática del WSDL desde su classpath es contrario al espíritu de WSDL, servicios web y JAX-WS, pero hay ocasiones en que es necesario.

Finalmente, si incrusta un WSDL estático, le sugiero que al menos haga que el punto final del servicio sea configurable para propósitos de prueba y despliegue. El código para reconfigurar el punto final de su cliente de servicio web es el siguiente:

YourClientInterface client = yourService.getPort( new QName("...", "..."), YourClientInterface.class); BindingProvider bp = (BindingProvider) client; bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8080/yourServiceEndpoint");


Si tu classpath tiene "." en él, luego Class.getResource (".") devolverá la URL del directorio desde el que ejecutó el comando java. Si no, le devolverá un nulo. Ajuste la wsdllocation en consecuencia.


Tal vez un poco tarde, pero encontré una solución bastante simple que funcionó para resolver este problema, pero esto implicó un cambio en el código generado de la clase de Servicio:

Si la siguiente línea en la clase de servicio

baseUrl = net.example.ApplicationService.class.getResource(".");

se cambia a

baseUrl = net.example.ApplicationService.class.getResource("");

funciona bien incluso con un WSDL que está empaquetado dentro de un JAR. No estoy seguro sobre el supuesto comportamiento exacto de getResource () en ninguno de estos casos, pero hasta ahora no experimenté ningún problema con este enfoque, en múltiples versiones de SO y Java.