JAX-WS Annotations Example
In this example we shall learn some important JAX-WS annotations provided by Java. To understand this tutorial, following is the prerequisite knowledge required:
- Basic knowledge of how to use annotations
- Basic SOAP Architecture
Table Of Contents
1. JAX-WS annotations
1.1 @WebService
This JAX-WS annotation can be used in 2 ways. If we are annotating this over a class, it means that we are trying to mark the class as the implementing the Web Service, in other words Service Implementation Bean (SIB). Or we are marking this over an interface, it means that we are defining a Web Service Interface (SEI), in other words Service Endpoint Interface.
Now lets see the java program demonstrating both of the mentioned ways:
WSAnnotationWebServiceI.java
package com.javacodegeeks.examples.jaxWsAnnotations.webservice; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style=Style.RPC) public interface WSAnnotationWebServiceI { @WebMethod float celsiusToFarhenheit(float celsius); }
In the above program we can see that we haven’t provided any optional element along with the @WebService
annotation. And here it is used to define SEI. Regarding the other annotations used in the above program, we shall see their description a little ahead.
WsAnnotationsWebServiceImpl.java
package com.javacodegeeks.examples.jaxWsAnnotations.webservice; import javax.jws.WebService; @WebService(endpointInterface="com.javacodegeeks.examples.jaxWsAnnotations.webservice.WSAnnotationWebServiceI") public class WsAnnotationsWebServiceImpl implements WSAnnotationWebServiceI { @Override public float celsiusToFarhenheit(float celsius) { return ((celsius - 32)*5)/9; } }
In the above program we can see that we have provided an optional element endpointInterface
along with the @WebService
annotation. And here it is used to define SIB. endpointInterface
optional element describes the SEI that the said SIB is implementing.
While implementing a web service as in above example, it is not mandatory for WsAnnotationsWebServiceImpl
to implement WSAnnotationWebServiceI
, this just serves as a check. Also, it is not mandatory to use an SEI, however, as a basic design principle “We should program to interface”, hence we have adapted this methodology in above program.
Other optional elements to @WebService
can be like wsdlLocation
that defines location of pre-defined wsdl defining the web service, name
that defines name of the web service etc.
1.2 @SOAPBinding
Demonstration of @SOAPBinding
JAX-WS annotation has already been shown in first program in 1.1. This annotation is used to specify the SOAP messaging style
which can either be RPC
or DOCUMENT
. This style represents the encoding style of message sent to and fro while using the web service.
With RPC
style a web service is capable of only using simple data types like integer or string. However, DOCUMENT
style is capable of richer data types for a class let’s say Person, which can have attributes like String name
, Address address
etc.
Document
style indicates that in the underlying web service, underlying message shall contain full XML documents, whereas in the RPC
style, the underlying message contains parameters and return values in request and response message respectively. By default the style
is Document
.
The other important optional attribute is use
. It represents the formatting style of the web service message. Its value can either be literal
or encoded
.
Example usage of @SOAPBinding:
@SOAPBinding(style=Style.DOCUMENT, use=Use.LITERAL)
1.3 @WebMethod
@WebMethod
JAX-WS annotation can be applied over a method only. This specified that the method represents a web service operation. For its demonstration, please refer to first program in 1.1.
1.4 @WebResult
To understand this JAX-WS annotation, let’s write SEI & SIB again:
WSAnnotationsWebResultI.java
package com.javacodegeeks.examples.jaxWsAnnotations.webresult; import javax.jws.WebMethod; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style = Style.RPC) public interface WSAnnotationsWebResultI { @WebMethod @WebResult(partName="farhenheitResponse") float celsiusToFarhenheit(float celsius); }
WSAnnotationsWebResultImpl.java
package com.javacodegeeks.examples.jaxWsAnnotations.webresult; import javax.jws.WebService; @WebService(endpointInterface="com.javacodegeeks.examples.jaxWsAnnotations.webresult.WSAnnotationsWebResultI") public class WSAnnotationsWebResultImpl implements WSAnnotationsWebResultI { @Override public float celsiusToFarhenheit(float celsius) { return ((celsius - 32)*5)/9; } }
Now let’s publish this endpoint:
WSPublisher.java
package com.javacodegeeks.examples.jaxWsAnnotations.webresult; import javax.xml.ws.Endpoint; public class WSPublisher { public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:9999/ctf", new WSAnnotationsWebResultImpl()); } }
On publishing the generated WSDL (at URL: http://127.0.0.1:9999/ctf?wsdl
) would be like:
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" name="WSAnnotationsWebResultImplService"> <types /> <message name="celsiusToFarhenheit"> <part name="arg0" type="xsd:float" /> </message> <message name="celsiusToFarhenheitResponse"> <part name="farhenheitResponse" type="xsd:float" /> </message> <portType name="WSAnnotationsWebResultI"> <operation name="celsiusToFarhenheit"> <input wsam:Action="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/WSAnnotationsWebResultI/celsiusToFarhenheitRequest" message="tns:celsiusToFarhenheit" /> <output wsam:Action="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/WSAnnotationsWebResultI/celsiusToFarhenheitResponse" message="tns:celsiusToFarhenheitResponse" /> </operation> </portType> <binding name="WSAnnotationsWebResultImplPortBinding" type="tns:WSAnnotationsWebResultI"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> <operation name="celsiusToFarhenheit"> <soap:operation soapAction="" /> <input> <soap:body use="literal" namespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" /> </input> <output> <soap:body use="literal" namespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" /> </output> </operation> </binding> <service name="WSAnnotationsWebResultImplService"> <port name="WSAnnotationsWebResultImplPort" binding="tns:WSAnnotationsWebResultImplPortBinding"> <soap:address location="http://127.0.0.1:9999/ctf" /> </port> </service> </definitions>
Refer to the highlighted line in above wsdl, the part name
has been changed to “farhenheitResponse
” as was defined using @WebResult
. What interest here is that @WebResult
can be used to determine what the generated WSDL shall look like.
If we comment out the @WebResult
, the WSDL (at URL: http://127.0.0.1:9999/ctf?wsdl
) shall be like:
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" name="WSAnnotationsWebResultImplService"> <types /> <message name="celsiusToFarhenheit"> <part name="arg0" type="xsd:float" /> </message> <message name="celsiusToFarhenheitResponse"> <part name="return" type="xsd:float" /> </message> <portType name="WSAnnotationsWebResultI"> <operation name="celsiusToFarhenheit"> <input wsam:Action="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/WSAnnotationsWebResultI/celsiusToFarhenheitRequest" message="tns:celsiusToFarhenheit" /> <output wsam:Action="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/WSAnnotationsWebResultI/celsiusToFarhenheitResponse" message="tns:celsiusToFarhenheitResponse" /> </operation> </portType> <binding name="WSAnnotationsWebResultImplPortBinding" type="tns:WSAnnotationsWebResultI"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> <operation name="celsiusToFarhenheit"> <soap:operation soapAction="" /> <input> <soap:body use="literal" namespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" /> </input> <output> <soap:body use="literal" namespace="http://webresult.jaxWsAnnotations.examples.javacodegeeks.com/" /> </output> </operation> </binding> <service name="WSAnnotationsWebResultImplService"> <port name="WSAnnotationsWebResultImplPort" binding="tns:WSAnnotationsWebResultImplPortBinding"> <soap:address location="http://127.0.0.1:9999/ctf" /> </port> </service> </definitions>
In the above program, part name
has value return
.
Other elements to @WebResult
are WebParam.Mode
that defines the direction in which parameter is flowing, targetNamespace
to define XML namespace for the parameter.
1.5 @WebServiceClient
To understand @WebServiceClient JAX-WS annotation, let us first publish the endpoint written in 1.1 using below program:
WSPublisher.java
package com.javacodegeeks.examples.jaxWsAnnotations.webservice; import javax.xml.ws.Endpoint; public class WSPublisher { public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:9999/ctf", new WsAnnotationsWebServiceImpl()); } }
Before moving further we should understand wsimport
utility provided by Java that eases the task of writing client for a SOAP based web service. We won’t go into much detail here about wsimport
, instead let’s first save the wsdl file with name ‘ctf.wsdl’ and then write following command on the command prompt:
wsimport -keep -p client ctf.wsdl
The generated code shall have following classes generated:
Now let’s open WsAnnotationsWebServiceImplService.java
. It shall be like:
WsAnnotationsWebServiceImplService.java
package client;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035
* Generated source version: 2.2
*
*/
@WebServiceClient(name = "WsAnnotationsWebServiceImplService", targetNamespace = "http://webservice.jaxWsAnnotations.examples.javacodegeeks.com/", wsdlLocation = "file:/Users/saurabharora123/Downloads/ctf.wsdl")
public class WsAnnotationsWebServiceImplService extends Service {
private final static URL WSANNOTATIONSWEBSERVICEIMPLSERVICE_WSDL_LOCATION;
private final static WebServiceException WSANNOTATIONSWEBSERVICEIMPLSERVICE_EXCEPTION;
private final static QName WSANNOTATIONSWEBSERVICEIMPLSERVICE_QNAME = new QName(
"http://webservice.jaxWsAnnotations.examples.javacodegeeks.com/", "WsAnnotationsWebServiceImplService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("file:/Users/saurabharora123/Downloads/ctf.wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
WSANNOTATIONSWEBSERVICEIMPLSERVICE_WSDL_LOCATION = url;
WSANNOTATIONSWEBSERVICEIMPLSERVICE_EXCEPTION = e;
}
public WsAnnotationsWebServiceImplService() {
super(__getWsdlLocation(), WSANNOTATIONSWEBSERVICEIMPLSERVICE_QNAME);
}
public WsAnnotationsWebServiceImplService(WebServiceFeature... features) {
super(__getWsdlLocation(), WSANNOTATIONSWEBSERVICEIMPLSERVICE_QNAME, features);
}
public WsAnnotationsWebServiceImplService(URL wsdlLocation) {
super(wsdlLocation, WSANNOTATIONSWEBSERVICEIMPLSERVICE_QNAME);
}
public WsAnnotationsWebServiceImplService(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, WSANNOTATIONSWEBSERVICEIMPLSERVICE_QNAME, features);
}
public WsAnnotationsWebServiceImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public WsAnnotationsWebServiceImplService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
/**
*
* @return returns WSAnnotationWebServiceI
*/
@WebEndpoint(name = "WsAnnotationsWebServiceImplPort")
public WSAnnotationWebServiceI getWsAnnotationsWebServiceImplPort() {
return super.getPort(new QName("http://webservice.jaxWsAnnotations.examples.javacodegeeks.com/",
"WsAnnotationsWebServiceImplPort"), WSAnnotationWebServiceI.class);
}
/**
*
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure
* on the proxy. Supported features not in the
* features
parameter will have their default
* values.
* @return returns WSAnnotationWebServiceI
*/
@WebEndpoint(name = "WsAnnotationsWebServiceImplPort")
public WSAnnotationWebServiceI getWsAnnotationsWebServiceImplPort(WebServiceFeature... features) {
return super.getPort(new QName("http://webservice.jaxWsAnnotations.examples.javacodegeeks.com/",
"WsAnnotationsWebServiceImplPort"), WSAnnotationWebServiceI.class, features);
}
private static URL __getWsdlLocation() {
if (WSANNOTATIONSWEBSERVICEIMPLSERVICE_EXCEPTION != null) {
throw WSANNOTATIONSWEBSERVICEIMPLSERVICE_EXCEPTION;
}
return WSANNOTATIONSWEBSERVICEIMPLSERVICE_WSDL_LOCATION;
}
}
Refer to the highlighted line in the above generated program that has the annotation @WebServiceClient
. The information specified in this annotation helps in identifying a wsdl:service element inside a WSDL document. This element represents the Web service for which the generated service interface provides a client view.
1.6 @RequestWrapper
@RequestWrapper
JAX-WS annotation is used to annotate methods in the Service Endpoint Interface with the request wrapper bean to be used at runtime. It has 4 optional elements; className
that represents the request wrapper bean name, localName
that represents element’s local name, partName
that represent the part name of the wrapper part in the generated WSDL file, and targetNamespace
that represents the element’s namespace.
Example usage: WSRequestWrapperInterface.java
package com.javacodegeeks.examples.jaxWsAnnotations.wrapper; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; import javax.xml.ws.RequestWrapper; @WebService @SOAPBinding(style=Style.RPC) public interface WSRequestWrapperInterface { @WebMethod @RequestWrapper(localName="CTF", targetNamespace="http://javacodegeeks.com/tempUtil", className="com.javacodegeeks.examples.jaxWsAnnotations.webservice.CTF") float celsiusToFarhenheit(float celsius); }
1.7 @ResponseWrapper
@ResponseWrapper
JAX-WS annotation is used to annotate methods in the Service Endpoint Interface with the response wrapper bean to be used at runtime. It has 4 optional elements; className
that represents the response wrapper bean name, localName
that represents element’s local name, partName
that represent the part name of the wrapper part in the generated WSDL file, and targetNamespace
that represents the element’s namespace.
Example usage: WSRequestWrapperInterface.java
package com.javacodegeeks.examples.jaxWsAnnotations.wrapper; import javax.jws.WebMethod; import javax.xml.ws.ResponseWrapper; public interface WSResponseWrapperInterfaceI { @WebMethod @ResponseWrapper(localName="CTFResponse", targetNamespace="http://javacodegeeks.com/tempUtil", className="com.javacodegeeks.examples.jaxWsAnnotations.webservice.CTFResponse") float celsiusToFarhenheit(float celsius); }
1.8 @Oneway
@Oneway
JAX-WS annotation is applied to WebMethod which means that method will have only input and no output. When a @Oneway
method is called, control is returned to calling method even before the actual operation is performed. It means that nothing will escape method neither response neither exception.
Example usage: WSAnnotationsOnewayI.java
package com.javacodegeeks.examples.jaxWsAnnotations.oneway; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style = Style.RPC) public interface WSAnnotationsOnewayI { @WebMethod @Oneway void sayHello(); }
1.9 @HandlerChain
Web Services and their clients may need to access the SOAP message for additional processing of the message request or response. A SOAP message handler provides a mechanism for intercepting the SOAP message during request and response.
A handler at server side can be a validator. Let’s say we want to validate the temperature before the actual service method is called. To do this our validator class shall implement interface SOAPHandler
TemperatureValidator.java
package com.javacodegeeks.examples.jaxWsAnnotations.handler; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class TemperatureValidator implements SOAPHandler { @Override public boolean handleMessage(SOAPMessageContext context) { // TODO Auto-generated method stub return false; } @Override public boolean handleFault(SOAPMessageContext context) { // TODO Auto-generated method stub return false; } @Override public void close(MessageContext context) { // TODO Auto-generated method stub } @Override public Set getHeaders() { // TODO Auto-generated method stub return null; } }
Next we shall implement SOAP handler xml file that may also contain sequence of handlers.
soap-handler.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <javaee:handler-chain> <javaee:handler> <javaee:handler-class>com.javacodegeeks.examples.jaxWsAnnotations.handler.TemperatureValidator </javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
After this we shall configure @HandlerChain
JAX-WS annotation in SEI:
WSAnnotationsHandlerChainI.java
package com.javacodegeeks.examples.jaxWsAnnotations.handler; import javax.jws.HandlerChain; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style = Style.RPC) public interface WSAnnotationsHandlerChainI { @HandlerChain(file = "soap-handler.xml") @WebMethod float celsiusToFarhenheit(float celsius); }
2. Directory structure of this example
The directory structure of the above example in eclipse shall look like:
3. Download the source code
This was an example of JAX-WS annotations.
You can download the full source code of this example here: JaxWSAnnotationsExample