JAX-WS provides the wsgen
and wsimport
command-line tools to generate portable artifacts for
JAX-WS web services. When creating JAX-WS web services, you can start with either a WSDL file or an implementation bean
class.
If you start with an implementation bean class, use the wsgen
command-line
tool to generate all the web services provider artifacts, including a WSDL file if requested.
If you start with a WSDL file, use the wsimport
command-line tool to
generate all the web services artifacts for either the server or the client. The wsimport
command-line tool
processes the WSDL file with schema definitions to generate the portable artifacts, which include the service class, the
service endpoint interface class, and the JAXB 2.1 classes for the corresponding XML schema.
The wsimport
tool generates JAX-WS portable artifacts, such as:
Service Endpoint Interface (SEI)
Service
Exception class mapped from wsdl:fault
(if any)
Async Reponse Bean derived from response wsdl:message
(if any)
JAXB generated value types (mapped Java classes from schema types)
Syntax:
wsimport [options] <wsdl>
Options:
-d <directory>
Specify where to place generated output files
-b <path>
Specify external JAX-WS or JAXB binding files or additional schema files (Each <file>
must
have its own -b
)
-B <jaxbOption>
Pass this option to JAXB schema compiler.
-keep
Keep generated source code files. It is enabled when -s
option.
-p
Specifying a target package via this command-line option, overrides any wsdl and schema binding customization for package name and the default package name algorithm defined in the specification.
-s <directory>
Specify where to place generated source code files. -keep
is turned on with this option.
-wsdllocation <location>
@WebServiceClient.wsdlLocation
value.
Multiple JAX-WS and JAXB binding files can be specified using -b
option and they can be used to customize
various things like package names, bean names, etc.
Example:
wsimport -p stockquote http://java.boot.by/StockQuote?wsdl
This will generate the Java artifacts and compile them by importing the http://java.boot.by/StockQuote?wsdl
External Binding Declaration
External binding files are semantically equivalent to embedded binding declarations. When wsimport
processes
the WSDL document for which there is an external binding file, it internalizes the binding declarations defined in the
external binding file on the nodes in the WSDL document they target using the wsdlLocation
attribute. The
embedded binding declarations can exist in a WSDL file and an external binding file targeting that WSDL, but
wsimport
may give an error if, upon embedding the binding declarations defined in the external binding files,
the resulting WSDL document contains conflicting binding declarations.
Embedded Binding Declarations
Embedded binding declarations follow different rules compared to the binding declarations declared in the external binding file. Here are some important facts and rules as defined in the JAX-WS 2.0 specification:
An embedded binding declaration is specified by using the jaxws:bindings
element as a WSDL
extension.
When a jaxws:bindings
element is used as a WSDL extension, it must not have a node attribute.
The binding declaration must not have a child element whose qualified name is jaxws:bindings
.
A binding declaration embedded in a WSDL can only affect the WSDL element it extends.
Here's an example of embedded binding declarations in the WSDL:
<wsdl:portType name="AddNumbersImpl"> <!-- wsdl:portType customizations --> <jaxws:bindings xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"> <!-- rename the generated SEI from AddNumbersImpl to MathUtil --> <jaxws:class name="MathUtil"/> ... </jaxws:bindings> <wsdl:operation name="addNumber"> ... </wsdl:portType>
The above WSDL file excerpt shows the wsdl:portType
customization. jaxws:bindings
appears as
extension element of portType
. It customizes the class name of the generated service endpoint interface.
Without this customization, or by default, the service endpoint interface class is named after the
wsdl:portType
name. The binding declaration jaxws:class
customizes the generated class to be
named MathUtil
instead of AddNumberImpl
.
Package Customization
By default wscompile
generates WSDL artifacts in a package computed from the WSDL
targetNamespace
. For example, a WSDL file with the targetNamespace
http://java.boot.by
without any package customization will be mapped to the by.boot.java
package. To customize the default package mapping you would use a jaxws:package
customization on the
wsdl:definitions
node or it can directly appear inside the top level bindings element.
An important thing to note is that -p
option on command-line wsimport
tool
(package
attribute on wsimport
Ant task), overrides the
jaxws:package
customization, it also overrides the schema package customization specified using JAXB
schema customization.
For example:
<bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL" xmlns="http://java.sun.com/xml/ns/jaxws"> <package name="by.boot.java"> <javadoc>Mathutil package</javadoc> </package> ... </bindings>
or:
<bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <package name="by.boot.java"> <javadoc>Mathutil package</javadoc> </package> ... </bindings> </bindings>
Wrapper Style
wsimport
by default applies wrapper style rules to the abstract operation defined in the
wsdl:portType
, and if an operation qualifies the Java method signature is generated accordingly. Wrapper
style Java method generation can be disabled by using jaxws:enableWrapperStyle
.
jaxws:enableWrapperStyle
can appear on the toplevel bindings
element
(with @wsdlLocation
attribute), it can also appear on the following target nodes:
wsdl:definitions
: global scope, applies to all the wsdl:operations
of all
wsdl:portType
attributes.
wsdl:portType
applies to all the wsdl:operations
in the portType
.
wsdl:operation
applies to only this wsdl:operation
.
For example:
<bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:8080/jaxws-external-customize/addnumbers?WSDL" xmlns="http://java.sun.com/xml/ns/jaxws"> <!-- applies to wsdl:definitions node, that would mean the entire wsdl --> <enableWrapperStyle>true</enableWrapperStyle> <!-- wsdl:portType operation customization --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']"> <!-- change java method name from addNumbers() to add() --> <enableWrapperStyle>false</enableWrapperStyle> ... </bindings> </bindings>
In the example above the wrapper style is disabled for the addNumbers
operation in AddNumbersImpl
portType
. This is because wsimport
processes this binding in the following order: first
wsdl:operation
, then its parent wsdl:portType
, and finally wsdl:definitions
. Here
wsdl:operation
addNumbers
has this customization disabled so this is what is applied by
wsimport
to generate a bare Java method signature.
Class Customization
The generated class for wsdl:portType
, wsdl:fault
, soap:headerfault
, and
wsdl:server
can be customized using the jaxws:class
binding declaration.
The Service Endpoint Interface Class
wscompile
will generate the service endpoint interface class MathUtil
instead of the default
AddNumbersImpl
in this example:
<!-- wsdl:portType customization --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']"> <!-- change the generated SEI class --> <class name="MathUtil"> <javadoc>Perform mathematical computations</javadoc> </class> ... </bindings>
The Exception Class
wsimport
will generate the MathUtilException
class instead of the default
AddNumbersExeption
in this example:
<!-- change the generated exception class name --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']/wsdl:fault[@name='AddNumbersException']"> <class name="MathUtilException"> <javadoc>Exception generated during computation</javadoc> </class> </bindings>
The Service Class
wsimport
will generate MathUtilService
instead of the default
AddNumbersService
in this example:
<!-- wsdl:service customization --> <bindings node="wsdl:definitions/wsdl:service[@name='AddNumbersService']"> <!-- change the generated service class --> <class name="MathUtilService"> <javadoc>Service to perform mathematical computations</javadoc> </class> </bindings>
Inline Customizations
Customizations to JAXB bindings made by means of inline binding declarations in an XML schema file take the form of
<xsd:appinfo>
elements embedded in schema <xsd:annotation>
elements
(xsd:
is the XML schema namespace prefix, as defined in W3C XML Schema Part 1: Structures). The general
form for inline customizations is shown below:
<xsd:annotation> <xsd:appinfo> . . binding declarations . . </xsd:appinfo> </xsd:annotation>
Customizations are applied at the location at which they are declared in the schema. For example, a declaration at the
level of a particular element would apply to that element only. Note that the XML Schema namespace prefix must be used
with the <annotation>
and <appinfo>
declaration tags. In the example above,
xsd:
is used as the namespace prefix, so the declarations are tagged <xsd:annotation>
and <xsd:appinfo>
.
External Binding Customization Files
Customizations to JAXB bindings made by means of an external file containing binding declarations take the general form shown below:
<jxb:bindings schemaLocation = "xsd:anyURI"> <jxb:bindings node = "xsd:string">* <binding declaration> <jxb:bindings> </jxb:bindings>
schemaLocation
is a URI reference to the remote schema.
node
is an XPath 1.0 expression that identifies the schema node within schemaLocation to which the
given binding declaration is associated.
For example, the first schemaLocation/node
declaration in a JAXB binding declarations file specifies the
schema name and the root schema node:
<jxb:bindings schemaLocation="po.xsd" node="/xsd:schema">
A subsequent schemaLocation/node
declaration, say for a simpleType
element named
ZipCodeType
in the above schema, would take the form:
<jxb:bindings node="//xsd:simpleType[@name='ZipCodeType']">
Customization files containing binding declarations are passed to the JAXB Binding compiler, xjc
,
using the following syntax:
xjc -b <file> <schema>
where <file>
is the name of binding customization file, and <schema>
is the name
of the schema(s) you want to pass to the binding compiler.
You can have a single binding file that contains customizations for multiple schemas, or you can break the customizations into multiple bindings files:
xjc schema1.xsd schema2.xsd schema3.xsd -b bindings123.xjb
xjc schema1.xsd schema2.xsd schema3.xsd -b bindings1.xjb -b bindings2.xjb -b bindings3.xjb
Note that the ordering of schema files and binding files on the command line does not matter, although each binding
customization file must be preceded by its own -b
switch on the command line.
javax.xml.ws.WebServiceContext
The javax.xml.ws.WebServiceContext
interface makes it possible for an endpoint implementation object and potentially
any other objects that share its execution context to access information pertaining to the request being served.
The WebServiceContext
is treated as an injectable resource that can be set at the time an endpoint is
initialized. The WebServiceContext
object will then use thread-local information to return the correct
information regardless of how many threads are concurrently being used to serve requests addressed to the
same endpoint object.
In Java SE, the resource injection denoted by the WebServiceContext
annotation is REQUIRED to take
place only when the annotated class is an endpoint implementation class.
The following code shows a simple endpoint implementation class which requests the injection of its
WebServiceContext
:
@WebService public class Test { @Resource private WebServiceContext context; public String reverse(String inputString) { MessageContext mc = context.getMessageContext(); ServletContext servletContext = (ServletContext) mc.get(MessageContext.SERVLET_CONTEXT); ... } }
The @javax.annotation.Resource
annotation defined by JSR-250 is used to request injection of the
WebServiceContext
. Then invoke the getMessageContext()
method and work with the
MessageContext
object.
URL patterns
The web.xml
file contains information about the structure and external dependencies of web components in the
module and describes how the components are used at run time. For Java API for XML-Based Web Services (JAX-WS) applications,
you can customize the URL pattern in the web.xml
file.
When you package a JAX-WS application as a web service, the web service is contained within a Web ARchive (WAR) file or a WAR module within an enterprise archive (EAR) file. A JAX-WS enabled WAR file contains the following items:
A WEB-INF/web.xml
file that describes configuration and deployment information for the web
components that comprise a web application.
Annotated classes that implement the web services contained in the application module including the service endpoint implementation class.
JAXB classes.
(Optional) Web Services Description Language (WSDL) documents that describe the web services contained in the application module.
(Optional) XML schema files.
(Optional) utility classes.
(Optional) web service clients.
The default URL pattern is defined by the @WebService.serviceName
attribute that is contained in your web
service implementation class. When the WSDL file that is associated with your service implementation class contains a
single port definition, you can choose to use the default URL pattern or you can customize the URL pattern within the
web.xml
file. When the WSDL file that is associated with your service implementation class contains
multiple port definitions within the same service definition, customized URL patterns are required. If you use the
default URL pattern when the service implementation class contains multiple port definitions, then multiple service
implementation classes are mapped to the same URL pattern which results in an error condition. You must edit the
web.xml
file and customize the URL patterns for each service definition. Each port maps to a web service
implementation class and to its own custom URL pattern. By customizing the URL pattern in the web.xml
file, you correct conflicting URL pattern definitions.
Determine if custom URL patterns are required or desired. Custom URL patterns are only required when the WSDL file for your JAX-WS web service contains multiple port definitions within a single service. Otherwise, you may optionally define custom URL patterns.
To customize the URL pattern for a service implementation class, edit the web.xml
file and
provide a <servlet>
and corresponding <servlet-mapping>
entry for
each JAX-WS web service implementation class for which a custom URL pattern is desired. You must define the
<url-pattern>
value within the <servlet-mapping>
entry.
The following example illustrates the required URL pattern customizations when the WSDL file associated with the service implementation class has multiple port definitions.
The following excerpt is from a sample web service implementation classes:
package by.boot.java; @WebService(serviceName="EchoService", portName="SOAP11EchoServicePort") public class EchoServiceSOAP11{ ... }
package by.boot.java; @WebService(serviceName="EchoService", portName="SOAP12EchoServicePort") public class EchoServiceSOAP12{ ... }
The following excerpt is from the WSDL file associated with the EchoServiceSOAP11
web service implementation
class. Each port in the WSDL file maps to a portName
in the web service implementation class:
<wsdl:service name="EchoService"> <wsdl:port name="SOAP11EchoServicePort" tns:binding="..." > ... </wsdl:port> <wsdl:port name="SOAP12EchoServicePort" tns:binding="..." > ... </wsdl:port> </wsdl:service>
In this scenario, because there are multiple port definitions within the WSDL file, you must customize the URL pattern
by editing the web.xml
file. Specify custom URL patterns for each service. The following excerpt is from
a sample web.xml
file that demonstrates setting up a servlet:
<servlet> <servlet-name>by.boot.java.EchoServiceSOAP11</servlet-name> <servlet-class>by.boot.java.EchoServiceSOAP11</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>by.boot.java.EchoServiceSOAP11</servlet-name> <url-pattern>/EchoServiceSOAP11</url-pattern> </servlet-mapping> <servlet> <servlet-name>by.boot.java.EchoServiceSOAP12</servlet-name> <servlet-class>by.boot.java.EchoServiceSOAP12</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>by.boot.java.EchoServiceSOAP12</servlet-name> <url-pattern>/EchoServiceSOAP12</url-pattern> </servlet-mapping>
Basic Authentication with JAX-WS
When a service that is constrained by HTTP basic authentication is requested, the server requests a user name and password from the client and verifies that the user name and password are valid by comparing them against a database of authorized users.
Annotating the Service
In this example, annotations are used to specify which users are authorized to access which methods of this
service. In this simple example, the @RolesAllowed
annotation is used to specify that users in
the application role of basicUser
are authorized access to the sayHello(String name)
method. This application role must be linked to a group of users on the Application Server.
The code snippet is as follows:
import javax.jws.WebMethod; import javax.jws.WebService; import javax.annotation.security.RolesAllowed; @WebService() public class Hello { private String message = new String("Hello, "); @WebMethod() @RolesAllowed("basicUser") public String sayHello(String name) { return message + name + "."; } }
The @RolesAllowed
annotation specifies that only users in the role of basicUser
will be allowed to access the sayHello(String name)
method. A @RolesAllowed
annotation implicitly declares a role that will be referenced in the application, therefore, no
@DeclareRoles
annotation is required.
Adding Security Elements to the Deployment Descriptor
To enable basic authentication for the service, add security elements to the application deployment descriptor,
WEB-INF/web.xml
. The security elements that need to be added to the deployment descriptor include
the <security-constraint>
and <login-config>
elements:
<?xml version="1.0" encoding="UTF-8"?> <web-app> <listener> <listener-class> com.sun.xml.ws.transport.http.servlet.WSServletContextListener </listener-class> </listener> <servlet> <display-name>HelloService</display-name> <servlet-name>HelloService</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloService</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <security-constraint> <display-name>SecurityConstraint</display-name> <web-resource-collection> <web-resource-name>WRCollection</web-resource-name> <url-pattern>/hello</url-pattern> </web-resource-collection> <auth-constraint> <role-name>basicUser</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-constraint>BASIC</auth-constraint> <realm-name>file</realm-name> </login-config> </web-app>
Linking Roles to Groups
The role of basicUser
has been defined for this application, but there is no group of
basicUser
defined for the Application Server. To map the role that is defined for the application
(basicUser
) to a group that is defined on the Application Server (user
), add
a <security-role-mapping>
element to the runtime deployment descriptor,
WEB-INF/sun-web.xml
, as shown below:
<?xml version="1.0" encoding="UTF-8"?> <sun-web-app error-url=""> <context-root>/helloservice</context-root> <class-loader delegate="true"/> <security-role-mapping> <role-name>basicUser</role-name> <group-name>user</group-name> </security-role-mapping> </sun-web-app>
Client
Sample client against the secured web service:
import javax.xml.ws.WebServiceRef;
import javax.xml.ws.BindingProvider;
public class HelloClient {
@WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
static HelloService service;
public static void main(String[] args) {
try {
Hello port = service.getHelloPort();
// Cast the proxy to a BindingProvider
BindingProvider prov = (BindingProvider) port;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "mikalai");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "secret");
String response = port.sayHello("Mikalai");
} catch(Exception e) {
e.printStackTrace();
}
}
}
There is one tricky aspect to the client: the use of the wsimport
utility to generate the JAX-WS
artifacts. The problem is that the web service's WSDL is also secured and therefore requires authentication
for access. There are workarounds, of course. One option is to generate the WSDL locally by using the
wsgen
utility on the SIB. Another option is to get the WSDL from a nonsecure version of the
service. The locally saved WSDL and its XSD are then fed into wsimport
to generate the artifacts.
The client application HelloClient
uses the BindingProvider
constants as keys for
the username and password. JAX-WS runrime expects the lookup keys for the username and password to be
the strings:
javax.xml.ws.security.auth.username javax.xml.ws.security.auth.password
These are the values of the BindingProvider
constant USERNAME_PROPERTY
and the
constant PASSWORD_PROPERTY
, respectively.
![]() |
![]() ![]() |