JAX-WS Tutorial for Beginners (original) (raw)

Java API for XML Web Services (JAX-WS) is a Java programming language for creating web services, particularly SOAP services. In this tutorial, we will build a multi-module Maven project to demonstrate how to create, deploy, consume, and test JAX-WS web services.

1. Introduction

Java API for XML Web Services (JAX-WS) is a Java programming language for creating web services, particularly SOAP services. JAX-WS 2.0 specification was introduced in 2005 and has been part of JDK since JDK6. JAX-WS uses annotations to simplify the development of web services.

JAX-WS provides the javax.jws.WebService annotation to define a class as a web service. A service endpoint interface (SEI) is an interface which defines the web methods that clients can invoke. An SEI is not required when building a JAX-WS endpoint. There are a few rules when developing JAX-WS web services:

In this example, I will demonstrate how to:

2. A Brief History of Web Services

Web services evolved from the Remote Procedure Call (RPC) mechanism in the Distributed Computing Environment (DCE) in the early 1990s. Common Object Request Broker Architecture (CORBA) and Microsoft’s Distributed COM are first-generation frameworks for DCE. Java Remote Method Invocation and Microsoft’s DotNet are second-generation frameworks for DCE. In 1998, Dave Winer of the UserLand Software developed XML-RPC, a technology innovation that marked the birth of web service. XML-RPC has two key features:

JAX-WS Tutorial - Web Service

Figure 1 Web Service

3. Technologies Used

The example code in this article was built and run using:

4. Maven Project

Apache Maven is a software project management and comprehension tool. It manages a project’s build, reporting, and documentation from a project object model (POM) file. In this step, I will create a jax-ws-tutorial Maven project with five modules:

Module Description Note
bottom-up Create and publish a web service with the Bottom-up approach.
employeeWsdlToJava Use wsimport to generate Java stubs from employee.wsdl.
top-down Create and publish a web service with the Top-down approach. depends on employeeWsdlToJava
tomcat-server Create and publish a web service in tomcat container. depends on employeeWsdlToJava
soapcClient Use wsimport to generate Java stubs from web services.
  1. Launch Eclipse and click File->New->Maven Project.
  2. At the pop-up window, select the POM package option, then enter the group Id: jcg.zheng.demo and artifact Id: jax-ws-tutorial, then click.Finish.
  3. You will see the Maven project: jax-ws-tutorial is created.
  4. Click File->New->Maven Module.
  5. At the pop-up windows, enter the module name: employeeWsdlToJava, then click Finish.
  6. You will see the Maven module: employeeWsdlToJavais created as a child of jax-ws-tutorial.
  7. Repeat steps 4 and 5 for bottom-up, top-down, tomcat-server , and soapClient.

4.1 Parent Project

The generated parent POM.xml includes five modules.

Pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT pom employeeWsdlToJava top-down bottom-up tomcat-server soapClient maven-compiler-plugin 3.5.1 1.8 1.8

5. Generated Stubs from Employee WSDL

JAX-WS provides WSDL-to-Java and Java-to-WSDL mapping tools. In this step, I will use wsimport to generate Java stubs from the employee.wsdl file. The generated source codes are saved into the src/main/java folder. Here is a quick guide on the mapping:

WSDL Java
namespace package
portType SEI
operation method
input parameter
output return
xsd:complextType Java beans

pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT employeeWsdlToJava org.codehaus.mojo jaxws-maven-plugin 2.5 employee_wsdl ${basedir}/src/main/resources/wsdl ${basedir}/src/main/resources/wsdl/employeeService.wsdl jcg.zheng.demo.service.employee.generated true ${basedir}/src/main/java wsimport

JAX-WS uses JAXB internally to convert Java objects to and from XMLs. Click here to learn more.

Generated Java Files

C:\gitworkspace\jax-ws-tutorial\employeeWsdlToJava\src\main\java\jcg\zheng\demo\service\employee\generated>dir Volume in drive C is OSDisk Volume Serial Number is 3A10-C6D4

Directory of C:\gitworkspace\jax-ws-tutorial\employeeWsdlToJava\src\main\java\jcg\zheng\demo\service\employee\generated

08/31/2018 03:57 PM . 08/31/2018 03:57 PM .. 08/31/2018 03:57 PM 1,822 EmployeeIdWrapper.java 08/31/2018 03:57 PM 4,116 EmployeeInfo.java 08/31/2018 03:57 PM 1,946 EmployeeInfoWrapper.java 08/31/2018 03:57 PM 1,287 EmployeeLookupService.java 08/31/2018 03:57 PM 3,492 EmployeeLookupService_Service.java 08/31/2018 03:57 PM 1,206 EmployeeType.java 08/31/2018 03:57 PM 3,524 ObjectFactory.java 08/31/2018 03:57 PM 205 package-info.java 08/31/2018 03:57 PM 1,207 UserDefinedException.java 08/31/2018 03:57 PM 1,438 UserDefinedFault.java 10 File(s) 20,243 bytes 2 Dir(s) 21,524,041,728 bytes free

C:\gitworkspace\jax-ws-tutorial\employeeWsdlToJava\src\main\java\jcg\zheng\demo\service\employee\generated>

6. Bottom-Up

With a Bottom-up approach, developers start programming the classes and business logic as Java codes and then generate the WSDL from it. It is easy to develop but hard to maintain as every change at the Java classes will alter the WSDL file. Developers can use a wsgen command to generate WSDL without publishing the web services.

In this step, I will create a HelloworldService class, annotate it with @WebService, and use wsgen to generate WSDL.

6.1 Pom.xml

No additional dependency is needed in the pom.xml.

pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT bottom-up jar

6.2 HelloWorldService

I will annotate the HelloWorldServiceImpl with @javax.jws.WebService and @javax.jws.WebMethod.

HelloWorldServiceImpl.java

package jcg.zheng.demo.service.impl;

import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService;

import jcg.zheng.demo.model.TopNews;

@WebService public class HelloWorldServiceImpl {

@WebMethod
public String hello(@WebParam(name = "name") String name) {
    return "Hello " + name + "!";
}

@WebMethod
public TopNews getTopNews() {
    TopNews tn = new TopNews();
    tn.setHighlights("Mary Zheng published an example for Jax-ws tutorial.");
    tn.setTitle("Jax-WS Tutorial is Available");
    return tn;
}

}

The TopNews domain model is returned from getTopNews, so annotate it with @XmlRootElement.

TopNews.java

package jcg.zheng.demo.model;

import java.io.Serializable; import java.util.Date;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement public class TopNews implements Serializable {

private static final long serialVersionUID = -7846083786214239318L;
private String title;
private String highlights;
private Date newsDate;

public TopNews() {
    super();
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getHighlights() {
    return highlights;
}

public void setHighlights(String highlights) {
    this.highlights = highlights;
}

public Date getNewsDate() {
    return newsDate;
}

public void setNewsDate(Date newsDate) {
    this.newsDate = newsDate;
}

}

Note: Execute wsgen -verbose -keep -cp . jcg.zheng.demo.service.impl.HelloWorldServiceImpl -wsdl to generate WSDL.

6.3 Publish Web Service

I will create a ServerApp to invoke javax.xml.ws.Endpopint for publishing the HelloWorldServiceImpl service to http://localhost:9980/helloworld. Start it as a Java application.

ServerApp.java

package jcg.zheng.demo.app;

import javax.xml.ws.Endpoint;

import jcg.zheng.demo.service.impl.HelloWorldServiceImpl;

public class ServerApp { public static void main(String[] args) { Endpoint.publish("http://localhost:9980/helloworld", new HelloWorldServiceImpl()); System.out.println("HelloworldServices Started!"); } }

6.4 Demo with SoapUI

SoapUI is a great tool for testing web services. Click here to download it. We started the web services in step 6.3. In this step, I will create a new SOAP project:

  1. Click File->New SOAP Project
  2. Enter the Initial WSDL: http://localhost:9980/helloworld?wsdl and Click OK
  3. Expand the newly created project, then click employeeLookup, and Request 1
  4. A SOAP message is populated, replace ? with the test data
  5. Submit the request
  6. A response XML is returned.

SoapUI Input

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:impl="" title="undefined" rel="noopener noreferrer">http://impl.service.demo.zheng.jcg/"> soapenv:Header/ soapenv:Body impl:hello Mary

SoapUI Output

<S:Envelope xmlns:S="" title="undefined" rel="noopener noreferrer">http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:helloResponse xmlns:ns2="" title="undefined" rel="noopener noreferrer">http://impl.service.demo.zheng.jcg/"> Hello Mary!

7. Top-Down

With a Top-down approach, developers start with the WSDL file and generate the Java Stubs with wsimport. In this step, I will create EmployeeLookupServiceImpl_WSDL from the generated stubs in step 5.

7.1 Pom.xml

I will include employeeWsdlToJava as a dependency.

pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT top-down

<dependencies>
    <dependency>
        <groupId>jcg.zheng.demo</groupId>
        <artifactId>employeeWsdlToJava</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>

7.2 EmployeeLookupService

I will create an implementation class: EmployeeLookupServiceImpl_WSDL which implements EmployeeLookupService and annotates it with @WebService and sets the endpointInterface value as jcg.zheng.demo.service.employee.generated.EmployeeLookupService.

EmployeeLookupServiceImpl_WSDL .java

package jcg.zheng.demo.service.employee.impl;

import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random;

import javax.jws.WebService;

import jcg.zheng.demo.service.employee.generated.EmployeeIdWrapper; import jcg.zheng.demo.service.employee.generated.EmployeeInfo; import jcg.zheng.demo.service.employee.generated.EmployeeInfoWrapper; import jcg.zheng.demo.service.employee.generated.EmployeeLookupService; import jcg.zheng.demo.service.employee.generated.EmployeeType; import jcg.zheng.demo.service.employee.generated.ObjectFactory; import jcg.zheng.demo.service.employee.generated.UserDefinedException; import jcg.zheng.demo.service.employee.generated.UserDefinedFault;

@WebService(endpointInterface = "jcg.zheng.demo.service.employee.generated.EmployeeLookupService") public class EmployeeLookupServiceImpl_WSDL implements EmployeeLookupService { ObjectFactory of = new ObjectFactory();

@Override
public EmployeeInfoWrapper employeeLookup(EmployeeIdWrapper employeeIdList) throws UserDefinedException {
    if (employeeIdList.getEid().isEmpty()) {
        UserDefinedFault e = of.createUserDefinedFault();
        e.setMessage("Empty Employee ID");

        throw new UserDefinedException("Please enter at lease one employee Id", e);
    }

    EmployeeInfoWrapper eWrapper = of.createEmployeeInfoWrapper();

    List allEmps = getEmployees(employeeIdList.getEid());

    eWrapper.getEmployeeInfo().addAll(allEmps);

    return eWrapper;
}

private List getEmployees(List ids) {

    List emps = new ArrayList<>();
    for (String id : ids) {
        emps.add(buildDummyEmployee(id, EmployeeType.HOURLY));
    }

    return emps;
}

private EmployeeInfo buildDummyEmployee(String id, EmployeeType type) {
    EmployeeInfo emp = of.createEmployeeInfo();
    emp.setEid(id);
    Random rand = new Random();
    emp.setFirstName("FName_" + id);
    emp.setLastName("LName_" + id);
    emp.setType(type);
    emp.setHourlyRate(new BigDecimal(rand.nextInt(40)));
    return emp;
}

}

7.3 Publish Web Service

JAX-WS Endpoint class’s publish method is used to deploy the services to the address. In this step, we will publish EmployeeLookupServiceImpl_WSDL at http://localhost:9990/EmployeeLookupService.

ServerApp.java

package jcg.zheng.demo.service.employee.impl;

import javax.xml.ws.Endpoint;

public class ServerApp { public static void main(String[] args) { Endpoint.publish("http://localhost:9990/EmployeeLookupService", new EmployeeLookupServiceImpl_WSDL());

    System.out.println("EmployeeLookupService Started!");
}

}

7.4 Demo with SoapUI

Repeat step 6.4 for http://localhost:9990/EmployeeLookupService?wsdl and capture the SoapUI input and output:

Soap Request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:emp="" title="undefined" rel="noopener noreferrer">http://bestpay.payroll/employee"> soapenv:Header/ soapenv:Body emp:EmployeeIdList emp:eid12

Soap Response

<S:Envelope xmlns:S="" title="undefined" rel="noopener noreferrer">http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> 12 FName_12 LName_12 33 Hourly

8. Tomcat Server

In this step, I will deploy the JAX-WS web service into a Tomcat container.

8.1 Pom.xml

There are several dependencies must be included in order to deploy the web services into a tomcat container.

Pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT tomcat-server

<dependencies>
    <dependency>
        <groupId>jcg.zheng.demo</groupId>
        <artifactId>employeeWsdlToJava</artifactId>
        <version>${project.version}</version>
    </dependency>

    <!-- jax-ws maven dependency -->
    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>2.2.8</version>
    </dependency>
    <!-- servlet provided by tomcat -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-core</artifactId>
        <version>2.2.7</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.stream.buffer</groupId>
        <artifactId>streambuffer</artifactId>
        <version>1.5.3</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.sun.xml.ws/policy -->
    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>policy</artifactId>
        <version>2.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.gmbal</groupId>
        <artifactId>gmbal-api-only</artifactId>
        <version>3.2.0-b003</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.glassfish.ha/ha-api -->
    <dependency>
        <groupId>org.glassfish.ha</groupId>
        <artifactId>ha-api</artifactId>
        <version>3.1.9</version>
    </dependency>
</dependencies>
<packaging>war</packaging>

8.2 EmployeeService

I will create an EmployeeServiceImpl and annotate it with @WebService. This step is the same as step 7.2.

EmployeeServiceImpl.java

package jcg.zheng.demo.service;

import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random;

import javax.jws.WebService;

import jcg.zheng.demo.service.employee.generated.EmployeeIdWrapper; import jcg.zheng.demo.service.employee.generated.EmployeeInfo; import jcg.zheng.demo.service.employee.generated.EmployeeInfoWrapper; import jcg.zheng.demo.service.employee.generated.EmployeeLookupService; import jcg.zheng.demo.service.employee.generated.EmployeeType; import jcg.zheng.demo.service.employee.generated.ObjectFactory; import jcg.zheng.demo.service.employee.generated.UserDefinedException; import jcg.zheng.demo.service.employee.generated.UserDefinedFault;

@WebService(endpointInterface = "jcg.zheng.demo.service.employee.generated.EmployeeLookupService") public class EmployeeServiceImpl implements EmployeeLookupService { ObjectFactory of = new ObjectFactory();

@Override
public EmployeeInfoWrapper employeeLookup(EmployeeIdWrapper employeeIdList) throws UserDefinedException {
    if (employeeIdList.getEid().isEmpty()) {
        UserDefinedFault e = of.createUserDefinedFault();
        e.setMessage("Empty Employee ID");

        throw new UserDefinedException("Please enter at lease one employee Id", e);
    }

    EmployeeInfoWrapper eWrapper = of.createEmployeeInfoWrapper();

    List allEmps = getEmployees(employeeIdList.getEid());

    eWrapper.getEmployeeInfo().addAll(allEmps);

    return eWrapper;
}

private List getEmployees(List ids) {

    List emps = new ArrayList();
    for (String id : ids) {
        emps.add(buildDummyEmployee(id, EmployeeType.HOURLY));
    }

    return emps;
}

private EmployeeInfo buildDummyEmployee(String id, EmployeeType type) {
    EmployeeInfo emp = of.createEmployeeInfo();
    emp.setEid(id);
    Random rand = new Random();
    emp.setFirstName("FName_" + id);
    emp.setLastName("LName_" + id);
    emp.setType(type);
    emp.setHourlyRate(new BigDecimal(rand.nextInt(40)));
    return emp;
}

}

8.3 Web Configuration

In this step, I will configure both sun-jaxws.xml and web.xml.

sun-jaxws.xml

web.xml

<listener>
    <listener-class>
        com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>

<servlet>
    <servlet-name>JAXWSServlet</servlet-name>
    <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>JAXWSServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

8.4 Start the Web Services

Deploy tomcat-server-0.0.1-SNAPSHOT.war to a tomcat server. Start the tomcat instance and verify EmployeeService is up by browsing to http://localhost:8080/tomcat-server/employeeWS?wsdl.

Tomcat Server Log

Aug 31, 2018 8:44:53 PM org.apache.jasper.servlet.TldScanner scanJars INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. Aug 31, 2018 8:44:55 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate INFO: WSSERVLET14: JAX-WS servlet initializing Aug 31, 2018 8:44:55 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized INFO: WSSERVLET12: JAX-WS context listener initializing Aug 31, 2018 8:44:55 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized INFO: WSSERVLET12: JAX-WS context listener initializing Aug 31, 2018 8:44:55 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler [http-nio-8080] Aug 31, 2018 8:44:55 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler [ajp-nio-8009] Aug 31, 2018 8:44:55 PM org.apache.catalina.startup.Catalina start INFO: Server startup in 17520 ms

9. SOAP Client

Consuming a web service is very easy with the JAX-WS. We will generate the java stubs and use the generated class which is annotated with @WebServiceClient to consume the services.

pom.xml

4.0.0 jcg.zheng.demo jax-ws-tutorial 0.0.1-SNAPSHOT soapClient io.cucumber cucumber-java 2.3.1 test io.cucumber cucumber-junit 2.3.1 test junit junit 4.12 test
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <version>2.5</version>
            <executions>
                <execution>
                    <id>helloworld_wsdl</id>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                    <configuration>
                        <wsdlUrls>
                            <wsdlUrl>http://localhost:9980/helloworld?wsdl</wsdlUrl>
                        </wsdlUrls>
                        <keep>true</keep>
                        <packageName>jcg.demo.jaxws.client.helloworld</packageName>
                        <sourceDestDir>${basedir}/src/main/generated</sourceDestDir>
                    </configuration>
                </execution>
                <execution>
                    <id>employee_wsdl</id>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                    <configuration>
                        <wsdlUrls>
                            <wsdlUrl>http://localhost:9990/EmployeeLookupService?wsdl</wsdlUrl>
                        </wsdlUrls>
                        <keep>true</keep>
                        <packageName>jcg.demo.jaxws.client.employee</packageName>
                        <sourceDestDir>${basedir}/src/main/generated</sourceDestDir>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<profiles>
    <profile>
        <id>cucumber</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.9</version>
                    <configuration>
                        <includes>
                            <include>**/RunCukesTest.java</include>
                        </includes>
                        <skipAfterFailureCount>1</skipAfterFailureCount>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

9.1 Generate Stubs

Here are the generated Java files for HelloWorldService.

Generated Stub for HelloworldService

C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\helloworld>dir Volume in drive C is OSDisk Volume Serial Number is 3A10-C6D4

Directory of C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\helloworld

08/31/2018 04:59 PM . 08/31/2018 04:59 PM .. 08/31/2018 04:59 PM 756 GetTopNews.java 08/31/2018 04:59 PM 1,521 GetTopNewsResponse.java 08/31/2018 04:59 PM 1,358 Hello.java 08/31/2018 04:59 PM 1,492 HelloResponse.java 08/31/2018 04:59 PM 2,114 HelloWorldServiceImpl.java 08/31/2018 04:59 PM 3,504 HelloWorldServiceImplService.java 08/31/2018 04:59 PM 4,445 ObjectFactory.java 08/31/2018 04:59 PM 132 package-info.java 08/31/2018 04:59 PM 2,884 TopNews.java 9 File(s) 18,206 bytes 2 Dir(s) 21,555,847,168 bytes free

C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\helloworld>

Here are the generated Java files for EmployeeService.

Generated Stub for EmployeeService

C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\employee>dir Volume in drive C is OSDisk Volume Serial Number is 3A10-C6D4

Directory of C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\employee

08/31/2018 04:59 PM . 08/31/2018 04:59 PM .. 08/31/2018 04:59 PM 1,888 EmployeeIdWrapper.java 08/31/2018 04:59 PM 3,981 EmployeeInfo.java 08/31/2018 04:59 PM 2,015 EmployeeInfoWrapper.java 08/31/2018 04:59 PM 1,675 EmployeeLookupService.java 08/31/2018 04:59 PM 3,782 EmployeeLookupServiceImplWSDLService.java

08/31/2018 04:59 PM 1,195 EmployeeType.java 08/31/2018 04:59 PM 3,491 ObjectFactory.java 08/31/2018 04:59 PM 194 package-info.java 08/31/2018 04:59 PM 1,185 UserDefinedException.java 08/31/2018 04:59 PM 1,427 UserDefinedFault.java 10 File(s) 20,833 bytes 2 Dir(s) 21,555,965,952 bytes free

C:\gitworkspace\jax-ws-tutorial\soapClient\src\main\generated\jcg\demo\jaxws\client\employee>

9.2 Create Client Service

In this step, I will create a client service with the desired WSDL endpoint URL

EmployeeServiceclient.java

package jcg.zheng.demo.service.client;

import java.net.MalformedURLException; import java.net.URL;

import jcg.demo.jaxws.client.employee.*;

public class EmployeeServiceClient {

private String serviceUrl;

public EmployeeServiceClient(String serviceUrl) {
    super();
    this.serviceUrl = serviceUrl;
}

public EmployeeInfoWrapper employeeLookup(EmployeeIdWrapper employeeIdList) throws UserDefinedException {

    try {
        URL url = new URL(serviceUrl);
        EmployeeLookupServiceImplWSDLService empService = new EmployeeLookupServiceImplWSDLService(url);

        EmployeeLookupService eSrc = empService.getEmployeeLookupServiceImplWSDLPort();

        return eSrc.employeeLookup(employeeIdList);
    } catch (MalformedURLException e) {
        UserDefinedFault fault = new UserDefinedFault();
        fault.setMessage(e.getMessage());
        throw new UserDefinedException("caught MalformedURLException. ", fault);
    }

}

}

HelloServiceClient .java

package jcg.zheng.demo.service.client;

import java.net.MalformedURLException; import java.net.URL;

import jcg.demo.jaxws.client.helloworld.HelloWorldServiceImpl; import jcg.demo.jaxws.client.helloworld.HelloWorldServiceImplService; import jcg.demo.jaxws.client.helloworld.TopNews;

public class HelloServiceClient {

public TopNews getTopNews() throws MalformedURLException {

    URL url = new URL("http://localhost:9980/helloworld?wsdl");
    HelloWorldServiceImplService service = new HelloWorldServiceImplService(url);
    HelloWorldServiceImpl eSrc = service.getHelloWorldServiceImplPort();

    return eSrc.getTopNews();
}

}

Note: When the web service changes its WSDL, then clients must regenerate the Java stubs. I wrote another article for a dynamic web service client. Web services may take a long time to complete. Clients can use a callback to perform other tasks while waiting for the response. Click here for more details.

9.3 JUnit Tests

In this step, I will create a JUnit test for EmployeeServiceClient.

EmployeeServiceClientTest.java

package jcg.zheng.demo.service.client;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import jcg.demo.jaxws.client.employee.*;

public class EmployeeServiceClientTest { private EmployeeServiceClient client = new EmployeeServiceClient( "http://localhost:9990/EmployeeLookupService?wsdl");

@Test
public void employeeLookup_found() throws UserDefinedException {
    EmployeeIdWrapper employeeIdList = new EmployeeIdWrapper();
    employeeIdList.getEid().add("100");
    EmployeeInfoWrapper ret = client.employeeLookup(employeeIdList);
    assertEquals(1, ret.getEmployeeInfo().size());
    assertEquals("100", ret.getEmployeeInfo().get(0).getEid());
}

@Test(expected=UserDefinedException.class)
public void employeeLookup_not_found() throws UserDefinedException {
    EmployeeIdWrapper employeeIdList = new EmployeeIdWrapper();	 
    client.employeeLookup(employeeIdList);		 
}

}

9.4 Acceptance Tests

I will create two cucumber tests which generates a HTML report.

9.4.1 Feature Files

Cucumber feature files are easy to read and communicates better with business than JUnit tests.

Employee Feature

Feature: Employee Look Up Service @Employee @SMOKE Scenario Outline: When invoking employeeLookupService
Then should find the employee from the response

Examples: 
    | empId |
    | 12    | 
    

Hello Feature

Feature: HelloWorld Service @Helloworld @SMOKE Scenario: When invoking getTopNew Then the response code should be ok

9.4.2 Step Definitions

I will create a Java class to handle the step defintions.

Hello Feature

package jcg.demo.servicetest.step;

import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull;

import cucumber.api.java.en.Then; import cucumber.api.java.en.When; import jcg.demo.jaxws.client.employee.EmployeeIdWrapper; import jcg.demo.jaxws.client.employee.EmployeeInfoWrapper; import jcg.zheng.demo.service.client.EmployeeServiceClient;

public class EmployeeServiceStep { EmployeeServiceClient emClient = new EmployeeServiceClient("http://localhost:9990/EmployeeLookupService?wsdl"); private EmployeeInfoWrapper serviceResponse;

@When("^invoking employeeLookupService (.+)$")
public void invoking_employeeLookupService(String empId) throws Exception {

    EmployeeIdWrapper employeeIdList = new EmployeeIdWrapper();
    employeeIdList.getEid().add(empId);
    serviceResponse = emClient.employeeLookup(employeeIdList);

}

@Then("^should find the employee from the response$")
public void the_response_code_should_find_the_employee() throws Exception {
    assertNotNull(serviceResponse);
    assertNotNull(serviceResponse.getEmployeeInfo());
    assertEquals(1, serviceResponse.getEmployeeInfo().size());
}

}

9.4.3 Run the Cucumber Tests

I will create RunCukesTest and annotate it with @RunWith(Cucumber.class). Execute it with C:\gitworkspace\jax-ws-tutorial\soapClient>mvn install -P cucumber.

RunCukesTest.java

package jcg.demo.servicetest;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class) @CucumberOptions(tags = { "@SMOKE" }, features = "src/test/resources/features", plugin = { "html:target/cucumber" }) public class RunCukesTest {

}

9.4.4 Test Reports

Verify the cucumber reports.

JAX-WS Tutorial - Cucumber Report

Figure 2 Cucumber Report

10. JAX-WS Tutorial – Summary

In this article, I demonstrated how to create and consume web services using JAX-WS in a Maven project with both Top-down and Bottom-up approaches. Top-down approach is the preferred way, but developers usually use a Bottom-up approach to generate WSDL and revise it. Once the WSDL is finalized, developers complete it with a Top-down approach.

I also demonstrated how to deploy web services with a JAX-WS Endpoint as a standard Java application and deploy it in a Tomcat container. I also showed how to test the web services via SoapUI, Junit, and cucumber framework.

You may secure the web service. Click here for how to secure the web service with JAX-WS.

11. Download the Source Code

This tutorial consists of a Maven project to create, consume, and test the JAX-WS web services.