1. Overview
Java API for XML Web Services (JAX-WS) is a standardized API for creating and consuming SOAP (Simple Object Access Protocol) web services.
In this article, we’ll create a SOAP web service and connect to it using JAX-WS.
2. SOAP
SOAP is an XML specification for sending messages over a network. SOAP messages are independent of any operating system and can use a variety of communication protocols including HTTP and SMTP.
SOAP is XML heavy, hence best used with tools/frameworks. JAX-WS is a framework that simplifies using SOAP. It is part of standard Java.
3. Top-Down vs. Bottom-Up
There are two ways of building SOAP web services. We can go with a top-down approach or a bottom-up approach.
In a top-down (contract-first) approach, a WSDL document is created, and the necessary Java classes are generated from the WSDL. In a bottom-up (contract-last) approach, the Java classes are written, and the WSDL is generated from the Java classes.
Writing a WSDL file can be quite difficult depending on how complex your web service is. This makes the bottom-up approach an easier option. On the other hand, since your WSDL is generated from the Java classes, any change in code might cause a change in the WSDL. This is not the case for the top-down approach.
In this article, we’ll take a look at both approaches.
4. Web Services Definition Language (WSDL)
WSDL is a contract definition of the available services. It is a specification of input/output messages, and how to invoke the web service. It is language neutral and is defined in XML.
Let’s look at the major elements of a WSDL document.
4.1. Definitions
The definitions element is the root element of all WSDL documents. It defines the name, the namespace, etc. of the service and, as you can see, can be quite spacious:
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://jaxws.baeldung.com/"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsp="http://www.w3.org/ns/ws-policy"
xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://jaxws.baeldung.com/"
name="EmployeeService">
...
</definitions>
4.2. Types
The types element defines the data types used by the web service. WSDL uses XSD (XML Schema Definition) as the type system which helps with interoperability:
<definitions ...>
...
<types>
<xsd:schema>
<xsd:import namespace="http://jaxws.baeldung.com/"
schemaLocation = "http://localhost:8080/employeeservice?xsd=1" />
</xsd:schema>
</types>
...
</definitions>
4.3. Messages
The message element provides an abstract definition of the data being transmitted. Each message element describes the input or output of a service method and the possible exceptions:
<definitions ...>
...
<message name="getEmployee">
<part name="parameters" element="tns:getEmployee" />
</message>
<message name="getEmployeeResponse">
<part name="parameters" element="tns:getEmployeeResponse" />
</message>
<message name="EmployeeNotFound">
<part name="fault" element="tns:EmployeeNotFound" />
</message>
...
</definitions>
4.4. Operations and Port Types
The portType element describes each operation that can be performed and all the message elements involved. For example, the getEmployee operation specifies the request input, output and possible fault exception thrown by the web service operation:
<definitions ...>
...
<portType name="EmployeeService">
<operation name="getEmployee">
<input
wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeRequest"
message="tns:getEmployee" />
<output
wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeResponse"
message="tns:getEmployeeResponse" />
<fault message="tns:EmployeeNotFound" name="EmployeeNotFound"
wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployee/Fault/EmployeeNotFound" />
</operation>
....
</portType>
...
</definitions>
4.5. Bindings
The binding element provides protocol and data format details for each portType:
<definitions ...>
...
<binding name="EmployeeServiceImplPortBinding"
type="tns:EmployeeService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="getEmployee">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="EmployeeNotFound">
<soap:fault name="EmployeeNotFound" use="literal" />
</fault>
</operation>
...
</binding>
...
</definitions>
4.6. Services and Ports
The service element defines the ports supported by the web service. The port element in service defines the name, binding and the address of the service:
<definitions ...>
...
<service name="EmployeeService">
<port name="EmployeeServiceImplPort"
binding="tns:EmployeeServiceImplPortBinding">
<soap:address
location="http://localhost:8080/employeeservice" />
</port>
</service>
...
</definitions>
5. Top-Down (Contract-First) Approach
Let’s start with a top-down approach by creating a WSDL file employeeservicetopdown.wsdl. For the sake of simplicity, it has only one method:
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://topdown.server.jaxws.baeldung.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://topdown.server.jaxws.baeldung.com/"
qname="EmployeeServiceTopDown">
<types>
<xsd:schema
targetNamespace="http://topdown.server.jaxws.baeldung.com/">
<xsd:element name="countEmployeesResponse" type="xsd:int"/>
</xsd:schema>
</types>
<message name="countEmployees">
</message>
<message name="countEmployeesResponse">
<part name="parameters" element="tns:countEmployeesResponse"/>
</message>
<portType name="EmployeeServiceTopDown">
<operation name="countEmployees">
<input message="tns:countEmployees"/>
<output message="tns:countEmployeesResponse"/>
</operation>
</portType>
<binding name="EmployeeServiceTopDownSOAP"
type="tns:EmployeeServiceTopDown">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document"/>
<operation name="countEmployees">
<soap:operation
soapAction="http://topdown.server.jaxws.baeldung.com/
EmployeeServiceTopDown/countEmployees"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="EmployeeServiceTopDown">
<port name="EmployeeServiceTopDownSOAP"
binding="tns:EmployeeServiceTopDownSOAP">
<soap:address
location="http://localhost:8080/employeeservicetopdown"/>
</port>
</service>
</definitions>
5.1. Generating Web Service Source Files from WSDL
There are several ways to generate web service source files from a WSDL document.
One way is to use the wsimport tool which is part of JDK (at $JAVA_HOME/bin) till JDK 8.
From the command prompt:
wsimport -s . -p com.baeldung.jaxws.server.topdown employeeservicetopdown.wsdl
Command line options used: -p specifies the target package. -s specifies where to put the generated source files.
For later JDK versions, we can use jaxws-maven-plugin by MojoHaus as described here.
Alternatively, org.jvnet.jaxb2‘s maven-jaxb2-plugin can come in handy as detailed in Invoking a SOAP Web Service in Spring.
The generated files:
- EmployeeServiceTopDown.java – is the service endpoint interface (SEI) that contains method definitions
- ObjectFactory.java – contains factory methods to create instances of schema derived classes programmatically
- EmployeeServiceTopDown_Service.java – is the service provider class that can be used by a JAX-WS client
5.2. Web Service Endpoint Interface
The wsimport tool has generated the web service endpoint interface EmployeeServiceTopDown. It declares the web service methods:
@WebService(
name = "EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface EmployeeServiceTopDown {
@WebMethod(
action = "http://topdown.server.jaxws.baeldung.com/"
+ "EmployeeServiceTopDown/countEmployees")
@WebResult(
name = "countEmployeesResponse",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/",
partName = "parameters")
public int countEmployees();
}
5.3. Web Service Implementation
The wsimport tool has created the structure of the web service. We have to create the implementation of the web service:
@WebService(
name = "EmployeeServiceTopDown",
endpointInterface = "com.baeldung.jaxws.server.topdown.EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
public class EmployeeServiceTopDownImpl
implements EmployeeServiceTopDown {
@Inject
private EmployeeRepository employeeRepositoryImpl;
@WebMethod
public int countEmployees() {
return employeeRepositoryImpl.count();
}
}
6. Bottom-Up (Contract-Last) Approach
In a bottom-up approach, we have to create both the endpoint interface and the implementation classes. The WSDL is generated from the classes when the web service is published.
Let’s create a web service that will perform simple CRUD operations on Employee data.
6.1. The Model Class
The Employee model class:
public class Employee {
private int id;
private String firstName;
// standard getters and setters
}
6.2. Web Service Endpoint Interface
The web service endpoint interface which declares the web service methods:
@WebService
public interface EmployeeService {
@WebMethod
Employee getEmployee(int id);
@WebMethod
Employee updateEmployee(int id, String name);
@WebMethod
boolean deleteEmployee(int id);
@WebMethod
Employee addEmployee(int id, String name);
// ...
}
This interface defines an abstract contract for the web service. The annotations used:
- @WebService denotes that it is a web service interface
- @WebMethod is used to customize a web service operation
- @WebResult is used to customize name of the XML element that represents the return value
6.3. Web Service Implementation
The implementation class of the web service endpoint interface:
@WebService(endpointInterface = "com.baeldung.jaxws.EmployeeService")
public class EmployeeServiceImpl implements EmployeeService {
@Inject
private EmployeeRepository employeeRepositoryImpl;
@WebMethod
public Employee getEmployee(int id) {
return employeeRepositoryImpl.getEmployee(id);
}
@WebMethod
public Employee updateEmployee(int id, String name) {
return employeeRepositoryImpl.updateEmployee(id, name);
}
@WebMethod
public boolean deleteEmployee(int id) {
return employeeRepositoryImpl.deleteEmployee(id);
}
@WebMethod
public Employee addEmployee(int id, String name) {
return employeeRepositoryImpl.addEmployee(id, name);
}
// ...
}
7. Publishing the Web Service Endpoints
To publish the web services (top-down and bottom-up), we need to pass an address and an instance of the web service implementation to the publish() method of the javax.xml.ws.Endpoint class:
public class EmployeeServicePublisher {
public static void main(String[] args) {
Endpoint.publish(
"http://localhost:8080/employeeservicetopdown",
new EmployeeServiceTopDownImpl());
Endpoint.publish("http://localhost:8080/employeeservice",
new EmployeeServiceImpl());
}
}
We can now run EmployeeServicePublisher to start the web service. To make use of CDI features, the web services can be deployed as WAR file to application servers like WildFly or GlassFish.
8. Remote Web Service Client
Let’s now create a JAX-WS client to connect to the EmployeeService web service remotely.
8.1. Generating Client Artifacts
To generate JAX-WS client artifacts, we can once again use the wsimport tool:
wsimport -keep -p com.baeldung.jaxws.client http://localhost:8080/employeeservice?wsdl
The generated EmployeeService_Service class encapsulates the logic to get the server port using URL and QName.
8.2. Connecting to the Web Service
The web service client uses the generated EmployeeService_Service to connect to the server and make web service calls remotely:
public class EmployeeServiceClient {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/employeeservice?wsdl");
EmployeeService_Service employeeService_Service
= new EmployeeService_Service(url);
EmployeeService employeeServiceProxy
= employeeService_Service.getEmployeeServiceImplPort();
List<Employee> allEmployees
= employeeServiceProxy.getAllEmployees();
}
}
9. Conclusion
This article is a quick introduction to SOAP Web services using JAX-WS.
We have used both the bottom-up and top-down approaches to creating SOAP Web services using the JAX-WS API. We have also written a JAX-WS client that can remotely connect to the server and make web service calls.
The complete source code is available over on GitHub.