1. Información general
En este tutorial, aprenderemos cómo construir un cliente SOAP en Java con JAX-WS RI . Primero, generaremos el código del cliente usando la utilidad wsimport y luego lo probaremos usando un JUnit.
Para aquellos que están comenzando, nuestra introducción a JAX-WS proporciona una gran experiencia sobre el tema.
2. El servicio web
Antes de comenzar a construir un cliente, necesitamos un servidor. En este caso, un servidor que expone un servicio web JAX-WS.
Para el propósito de este tutorial, usaremos un servicio web que nos traerá los datos de un país, dado su nombre.
2.1. Resumen de implementación
Dado que nos enfocamos en construir el cliente, no entraremos en los detalles de implementación de nuestro servicio.
Baste decir que se utiliza una interfaz CountryService para exponer el servicio web al mundo externo. Para simplificar las cosas, crearemos e implementaremos el servicio web utilizando la API javax.xml.ws.Endpoint en nuestra clase CountryServicePublisher .
Ejecutaremos CountryServicePublisher como una aplicación Java para publicar un punto final que aceptará las solicitudes entrantes. En otras palabras, este será nuestro servidor.
Después de iniciar el servidor, presionar la URL // localhost: 8888 / ws / country? Wsdl nos da el archivo de descripción del servicio web. El WSDL actúa como una guía para comprender las ofertas del servicio y generar código de implementación para el cliente.
2.2. El lenguaje de descripción de servicios web
Veamos el WSDL de nuestro servicio web, país :
En pocas palabras, esta es la información útil que proporciona:
- podemos invocar el método findByName con un argumento de cadena
- en respuesta, el servicio nos devolverá un tipo de país personalizado
- los tipos se definen en un esquema xsd generado en la ubicación // localhost: 8888 / ws / country? xsd = 1 :
Eso es todo lo que necesitamos para implementar un cliente.
Veamos cómo en la siguiente sección.
3. Uso de wsimport para generar código de cliente
3.1. Complemento Maven
Primero, agreguemos un complemento a nuestro pom.xml para usar esta herramienta a través de Maven:
org.codehaus.mojo jaxws-maven-plugin 2.6 wsimport-from-jdk wsimport //localhost:8888/ws/country?wsdl true com.baeldung.soap.ws.client.generated src/main/java
En segundo lugar, ejecutemos este complemento:
mvn clean jaxws:wsimport
¡Eso es todo! El comando anterior generará código en el paquete especificado com.baeldung.soap.ws.client.generated dentro del sourceDestDir que proporcionamos en la configuración del complemento.
Otra forma de lograr lo mismo sería utilizar la utilidad wsimport . Viene de fábrica con la distribución estándar JDK 8 y se puede encontrar en el directorio JAVA_HOME / bin .
Para generar código de cliente usando wsimport , podemos navegar a la raíz del proyecto y ejecutar este comando:
JAVA_HOME/bin/wsimport -s src/main/java/ -keep -p com.baeldung.soap.ws.client.generated "//localhost:8888/ws/country?wsdl"
Es importante tener en cuenta que el punto final del servicio debe estar disponible para ejecutar correctamente el complemento o comando.
A continuación, veamos los artefactos generados.
3.2. POJO generados
Basado en el xsd que vimos anteriormente, la herramienta generará un archivo llamado Country.java :
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "country", propOrder = { "capital", "currency", "name", "population" }) public class Country { protected String capital; @XmlSchemaType(name = "string") protected Currency currency; protected String name; protected int population; // standard getters and setters }
Como podemos ver, la clase generada está decorada con anotaciones JAXB para ordenar y desagrupar el objeto hacia y desde XML.
Además, genera una enumeración de moneda :
@XmlType(name = "currency") @XmlEnum public enum Currency { EUR, INR, USD; public String value() { return name(); } public static Currency fromValue(String v) { return valueOf(v); } }
3.3. CountryService
El segundo artefacto generado es una interfaz que actúa como proxy del servicio web real.
La interfaz CountryService declara el mismo método que nuestro servidor, findByName :
@WebService(name = "CountryService", targetNamespace = "//server.ws.soap.baeldung.com/") @SOAPBinding(style = SOAPBinding.Style.RPC) @XmlSeeAlso({ ObjectFactory.class }) public interface CountryService { @WebMethod @WebResult(partName = "return") @Action(input = "//server.ws.soap.baeldung.com/CountryService/findByNameRequest", output = "//server.ws.soap.baeldung.com/CountryService/findByNameResponse") public Country findByName(@WebParam(name = "arg0", partName = "arg0") String arg0); }
En particular, la interfaz está marcada como javax.jws.WebService , con SOAPBinding.Style como RPC según lo definido por el WSDL del servicio.
El método findByName se anota para declarar que es un método javax.jws.WebMethod , con sus tipos de parámetros de entrada y salida esperados.
3.4. CountryServiceImplService
Nuestra siguiente clase generada, CountryServiceImplService , amplía javax.xml.ws.Service. Su anotación WebServiceClient denota que es la vista de cliente de un servicio:
@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "//server.ws.soap.baeldung.com/", wsdlLocation = "//localhost:8888/ws/country?wsdl") public class CountryServiceImplService extends Service { private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; private final static WebServiceException COUNTRYSERVICEIMPLSERVICE_EXCEPTION; private final static QName COUNTRYSERVICEIMPLSERVICE_QNAME = new QName("//server.ws.soap.baeldung.com/", "CountryServiceImplService"); static { URL url = null; WebServiceException e = null; try { url = new URL("//localhost:8888/ws/country?wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION = url; COUNTRYSERVICEIMPLSERVICE_EXCEPTION = e; } public CountryServiceImplService() { super(__getWsdlLocation(), COUNTRYSERVICEIMPLSERVICE_QNAME); } // other constructors @WebEndpoint(name = "CountryServiceImplPort") public CountryService getCountryServiceImplPort() { return super.getPort(new QName("//server.ws.soap.baeldung.com/", "CountryServiceImplPort"), CountryService.class); } private static URL __getWsdlLocation() { if (COUNTRYSERVICEIMPLSERVICE_EXCEPTION != null) { throw COUNTRYSERVICEIMPLSERVICE_EXCEPTION; } return COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; } }
El método importante a tener en cuenta aquí es getCountryServiceImplPort . Dado un nombre calificado del punto final del servicio, o QName , y el nombre de la interfaz del punto final del servicio del proxy dinámico, devuelve una instancia de proxy.
Para invocar el servicio web, necesitamos usar este proxy, como veremos en breve .
Using a proxy makes it seem as if we are calling a service locally, abstracting away the intricacies of remote invocation.
4. Testing the Client
Next, we'll write a JUnit test to connect to the web service using the generated client code.
Before we can do that, we need to get the service's proxy instance at the client end:
@BeforeClass public static void setup() { CountryServiceImplService service = new CountryServiceImplService(); CountryService countryService = service.getCountryServiceImplPort(); }
For more advanced scenarios such as enabling or disabling a WebServiceFeature, we can use other generated constructors for CountryServiceImplService.
Now let's look at some tests:
@Test public void givenCountryService_whenCountryIndia_thenCapitalIsNewDelhi() { assertEquals("New Delhi", countryService.findByName("India").getCapital()); } @Test public void givenCountryService_whenCountryFrance_thenPopulationCorrect() { assertEquals(66710000, countryService.findByName("France").getPopulation()); } @Test public void givenCountryService_whenCountryUSA_thenCurrencyUSD() { assertEquals(Currency.USD, countryService.findByName("USA").getCurrency()); }
Como podemos ver, invocar los métodos del servicio remoto se volvió tan simple como llamar a los métodos localmente. El método findByName del proxy devolvió una instancia de País que coincide con el nombre que proporcionamos. Luego, usamos varios captadores del POJO para afirmar los valores esperados.
5. Conclusión
En este tutorial, vimos cómo invocar un servicio web SOAP en Java usando JAX-WS RI y la utilidad wsimport .
Alternativamente, podemos usar otras implementaciones JAX-WS como Apache CXF, Apache Axis2 y Spring para hacer lo mismo.
Como siempre, el código fuente está disponible en GitHub.