JAX-WS (Java Architecture for Web Services) is a standards-based API for coding, assembling, and deploying Java Web services, designed to replace JAX-RPC. JAXB (Java Architecture for XML Binding) is a Java/XML binding technology. JAX-WS uses JAXB to handle all the Java binding chores.
This article provides an overview of the JAX-WS 2.0
and JAXB 2.0 support in BEA WebLogic Server 10.1. I include sample code to get you started.
Very Busy Java Developer's Guide to JAXB 2.0
JAX-WS uses JAXB to handle all the Java binding chores, so
I will primarily be discussing JAXB as it relates to JAX-WS. A skilled Java developer is typically also a very busy one. This
being the case, I'll limit the discussion to:
Stuff you can currently do with JAXB 2.0.
Stuff you can't currently do with JAXB 2.0.
For those of you who are too busy to even read this article, feel free to just go ahead and download the
article's Download sample code. There is a README file inside the zip, which walks
you through all the steps to get things working.
What Kind of Stuff Can You Do with JAXB 2.0?
Here's a list of some of the more interesting stuff you can do with JAXB 2.0.
This is not to say that you can't do the same things with other Java-to-XML/XML-to-Java binding
technologies. It's merely stating what you can do with JAXB 2.0:
Generate Java object graphs from a WSDL containing one or more <xs:schema> elements. These <xs:schema> elements can use <xs:import> and <xs:include> elements to reference other <xs:schema> elements.
Generate XML Schema documents from Java object graphs.
Leverage Fast Infoset parsers (SAX and StAX) and serializers.
Get random access to the XML infoset of an XML document.
Embed binding declarations directly in XML Schema files, or in an external binding customization file.
Use the event-based streaming model when unmarshalling.
Marshal binary data (for example, handle MTOM and MIME attachments).
Develop your own plug-ins to extend the JAXB code generation capabilities. These plug-ins (which are packaged as classes in a .jar file) can then access the code that JAXB generates, plus generate additional classes/methods/fields/annotations/comments.
Write custom code to transform existing classes into the classes generated by the JAXB schema compiler.
What Kind of Stuff Can't You Do with JAXB 2.0?
Here's a list of some of the stuff you can't (or I didn't see a way how to) do
with JAXB 2.0:
Generate an XML schema from an XML document. This is really not such a big deal, because other tools (like Stylus Studio, XMLSpy, XMLBuddy Pro) can do this.
Match the performance numbers of using StAX or SAX for parsing. When parsing the same XML document, SAX came in at 10ms, StAX at 46ms, and JAXB 2.0 at 59ms.
Sample POJO JAX-WS Web Service that Uses JAXB for Java Binding
JAX-WS is a standards-based API for coding, assembling, and deploying Java Web services. It uses
JAXB to handle all the Java binding chores associated with this.
JAX-WS 2.0/2.1 doesn't support the use of JAX-RPC or Apache Beehive XMLBean types—just
JAXB ones.
JAX-WS provides two programming models for developing a Web service endpoint:
Start from Java—This programming model provides you with a
lot of control over the Java data types used in the method signatures of your Web service endpoint.
Here, you hand-code (or use a tool to generate) the Java objects that will be used as the input
arguments and return value of Web service operations, along with JWS annotations.
BEA provides the jwsc Ant task for the "Start from Java" programming model. It
wraps (that is, invokes) the Glassfish wsimport Ant task internally, so I don't directly use
that Ant task in the build.xml.
The Ant
Task Reference for jwsc BEA documentation describes how to use the <jws> element's
type="JAXWS" attribute to generate JAXB artifacts. The jwsc Ant
task has a <binding> child element for specifying the JAXB binding customization file
to use.
Start from WSDLThis programming model generates
the skeleton code for your Web service endpoint, from the contents of a WSDL. The
<xs:schema> sections in the WSDL are used to generate the Java data types
used as the input arguments and return value, of Web service operations.
BEA provides the wsdlc Ant task for the "Start from WSDL" programming model. It
wraps the Glassfish wsimport Ant task internally, so I don't directly use
that Ant task in the build.xml.
The Ant
Task Reference for wsdlc BEA documentation describes how to use the <wsdlc>
element's type="JAXWS" attribute to generate JAXB artifacts.
The wsdlc Ant task has a <binding> child element for specifying
the JAXB binding customization file to use.
The remainder of the article walks through the process of creating, deploying, and testing a sample POJO-based (Plain-Old
Java Object) JAX-WS Web service endpoint, named DataStagingService.
Creating the Customization File
The first step involves creating a JAX-WS customization file. This doubles as a JAXB binding
customization file, and allows you to control the JAX-WS and JAXB build-time processes, as well as the
artifacts produced by them.
The customization file is an XML document that conforms to the XML schemas for the http://java.sun.com/xml/ns/jaxws
and http://java.sun.com/xml/ns/jaxb namespaces. You can find details on how to create this customization
file at JAX-WS 2.0 Beta Customizations.
The JAX-WS customization file for this DataStagingService Web service is pretty small, so I've included
it here:
I basically just use the customization file to control the Java package name of classes
that are generated. You can do a lot more than this in one of these files, so be sure to
check out JAX-WS
2.0 Beta Customizations.
The next listing contains the XML Schema used in the WSDL, for the DataStagingService
Web service:
The XML Schema section from this WSDL is pretty normal-looking. It's your basic garden variety,
global complexType elements (with anonymous and explicit content models) combined to create request
and response messages. DataStagingService is a doc/literal style Web service, so global
elements have been included for use with the WSDL's <part> element.
Building with a build.xml File
I'm going to be using the Eclipse IDE that ships with WebLogic Server 10 for the walk through.
WebLogic for Workshop 10 doesn't have a specific Eclipse IDE plug-in for JAX-WS and JAXB development,
so I'll use a build.xml Ant script and the Ant View window.
This build.xml is too long to embed in the article, so I'll present just noteworthy fragments of it.
The above listing points out the <path> element used in the build.xml. It
shows that WebLogic Server 10 uses shared Java EE library modules for the classes in its
JAX-WS and JAXB implementation. As you can see, these are classes from the Glassfish RI JARs, not
classes written by the WebLogic Server 10 Web Services stack development team. Shared Java EE
library modules facilitate packaging up the Glassfish JARs, and allow a single copy of them to be
used for multiple internal (to BEA) and external purposes. The ${BEA_HOME}/modules
directory is the well-known place for these library modules.
The JARs in the above listing were placed in a user-defined library to make it easier to write code
that uses the JAX-WS and JAXB APIs inside the Eclipse IDE.
Generating the JAX-WS Service Endpoint and JAXB Classes
The next step looks at the coding of the DataStagingService Web service.
It starts with running the BEA wsdlc Ant task, in order to produce a skeleton JAX-WS
endpoint implementation and the JAXB classes.
WebLogic Server 10.1 uses jars from the Glassfish Project for its JAX-WS and JAXB implementations.
The presence of the type="JAXWS" attribute is what causes JAX-WS and JAXB to
be used, instead of JAX-RPC.
The main things to note are the type="JAXWS" attribute and the <binding>
child element.
You should now be able to run the Ant build file. This will generate the code for the JAX-WS endpoint implementation. Because I supplied a customization file, the generated code will be in the com.acmeworld.irad.services.datastaging package. The full code for the JAX-WS endpoint implementation is too long to include here, but here's an extract:
public com.acmeworld.irad.services.datastaging.DataStagingResponse.OutputURIs dataStaging(com.acmeworld.irad.services.datastaging.DataStaging.InputURIs inputURIs)
{
DataStagingResponse dataStagingResponse = null;
InputStream inputstream = null;
try
{
//DataStaging.InputURIs contains zero or more
//DataStaging.InputURIs.InputURI JAXB objects.
//We loop through them, and use one of their getter
//methods to print out a bound value.
DataStaging.InputURIs.InputURI inputURI = null;
List inputURIList = inputURIs.getInputURI();
for (int i = 0; i < inputURIList.size(); i++)
{
inputURI = inputURIList.get(i);
log("dataStaging(InputURIs)", "inputURI.getUri()=" + inputURI.getUri());
}
//Next, we show one way to use the JAXB API, to convert
//the DataStaging.InputURIs input parameter to a byte[].
//This byte[] will contain an XML representation of that
//input parameter.
JAXBContext jc = JAXBContext.newInstance(DataStaging.InputURIs.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JAXBElement je = new JAXBElement(
new QName("http://services.irad.acmeworld.com/datastaging","inputURIs"),
DataStaging.InputURIs.class,
inputURIs
);
marshaller.marshal(je, baos);
//We use an existing XML file for the response from the
//Web service operation. We’ll load this XML file from
//the WEB-INF/classes directory, and use the JAXB API
//to create the JAXB object of our response.
inputstream = Thread.currentThread().getContextClassLoader().getResourceAsStream("SampleDataStagingResponseDocument.xml");
jc = JAXBContext.newInstance(DataStagingResponse.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
dataStagingResponse = (DataStagingResponse)unmarshaller.unmarshal(inputstream);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
if (inputstream != null) try {} catch (Exception e){}
}
return dataStagingResponse.getOutputURIs();
}
The code comments provide a pretty good explanation of what's going on, so I won't supply
any additional narrative here.
Compiling the JAX-WS Service Endpoint
The BEA jwsc Ant task is used to compile the JAX-WS service
endpoint and produce the WAR file that will be deployed.
Again, the main things to note are the type="JAXWS" attribute and the
<binding> child element. It also illustrates a way to avoid putting WebLogic-specific
annotations (for example, @WLHttpTransport) in the JWS.
Deploying with a build.xml File
One of the oft-touted features of JAX-WS is that it makes the use of deployment descriptors optional.
This is nice, because it removes portability issues between JAX-WS implementations provided by multiple
vendors.
POJO-based JAX-WS Web services are packaged as Java EE Web applications, and WebLogic Server 10 provides
a wsdeploy Ant task for deploying them to a running WLS instance. I leverage this
wsdeploy Ant task in the build.xml file I use here.
The WebLogic Test Client is a Java EE Web application, which, like the WebLogic Server Administration Console
(console.war), is automatically deployed in your WebLogic Server 10.1 instance. The URL for it is:
http://<host>:<port>/wls_utc
The URL for the WSDL of the DataStagingService is:
When you click the "Test" button after entering this WSDL URL, you'll be
presented with the page that lets you enter a test request XML. Here's a sample request
XML:
The WebLogic Test Client is cool, but it doesn't really provide any insight into how to use JAXB
and JAX-WS on the client side. The final walk-through step does that.
Testing with a JAX-WS Web Service Client
The final walk-through step looks at the JAX-WS Web service client used to invoke the
DataStagingService Web service. This ended up being a bit more complex than
the code for the JAX-WS service endpoint, when it came to using the JAXB API.
Most of the code is devoted to performing XSL transformations, using the JAXP API classes in the
JDK. It starts out by creating a DataStagingService service stub. It accepts a URL object
that points to the service endpoint's WSDL, and some XML-related for establishing the service being
called. The latter is used after the WSDL is retrieved.
Note that the DataStagingService service stub and related classes were generated by the
BEA clientgen Ant task. I don't show it here, but that Ant task has a type="JAXWS"
attribute and <binding> child element as well.
The remaining code in the extract covers:
Creating the Dispatch object that is used to invoke the Web service operation. The Dispatch object is functionally equivalent to the Call object (used with the DII programming model) in JAX-RPC.
Creating the payload from an XML document. This is a welcome departure from the "instantiate an object for each element" exercise, required for JAX-RPC.
Invoking the Web service operation. You'll need to be a little careful here, because there is no auto-magic adding of an "operation name" wrapper element. If the service endpoint expects one, you'll need to add it yourself.
Using JAXP transformation classes to marshal the response from the Web service operation into a java.io.ByteArrayOutputStream. From there, you can go wherever you need to go (for example, byte[], String, XML). Again, this is much less onerous than dealing with graphs of JavaBeans (or worse, javax.xml.soap.SOAPElement objects), like you have to do with JAX-RPC.
This concludes the walk through. Hopefully it has given you a better understanding of how to use the
JAX-WS 2.0 and JAXB 2.0 implementation in WebLogic Server 10. You've been able to see that these
implementations have APIs, which are used on both the service-provider and service-consumer side. When you
look at the sample code I've provided, you'll see that none of it uses (or imports) any WebLogic-specific
classes. This means that the code is completely portable and should compile on Axis2, without having to
make a single code (or customization file) change. You will, however, need to change the build.xml file,
to use the .jar files that Axis2 uses for its JAX-WS and JAXB implementation. You'll also need to change Ant
tasks used for JAX-WS, JAXB, and deployment.
A Few Best Practices
Here's a short list of best practices I've culled from using the JAX-WS and JAXB implementation in WebLogic
Server 10:
Avoid using vendor-specific annotations in code where possible. Doing this avoids having to make code changes
just to try out JAX-WS implementations from different vendors. JAX-WS implementation vendors typically provide ways to
access vendor-specific annotations in their Ant tasks. WebLogic Server uses that option, so you should leverage it
instead of using their vendor-specific annotations in your JWSs.
Use JAXP StreamSource and StreamResult, where possible.
The javax.xml.transform.stream.StreamSource and javax.xml.transform.stream.StreamResult classes
offer the most efficient way to deal with Java serialization (and deserialization) issues. This being the case, you should
use them whenever and wherever possible.
Cache JAXBContext objects. The javax.xml.bind.JAXBContext object is a factory for
creating JAXB objects from a Java class. It is a relatively expensive operation to create a JAXBContext object,
so you should cache them for reuse.
Use JAXBElement to marshal inner classes. JAXB 2.0 uses inner classes for anonymous complexType
elements. If you then use one of these in the method signature of a Web service operation, you will receive a javax.xml.bind.MarshalException
during the build. The problem is that the inner class(es) is not a top-level element, so it doesn't have a @XmlRootElement
annotation. The fix is to create a JAXBElement object for the inner class. Just do a search on "JAXBElement"
in the DataStagingServiceImpl.java file to get a feel for how to do this.
JAX-WS and JAXB are two of the most promising APIs for constructing next-generation, Java-based Web
services. The WebLogic Server 10 Web Services stack offers support for both of these APIs today, via
Glassfish JARs and BEA Ant tasks.
You can use the WebLogic Server 10 Web Services stack to write, build, and deploy JAX-WS Web services for
any JAX-WS implementation, not just the one in the WebLogic Server 10. The jwsc and wsdlc
Ant tasks have been modified to allow you to specify that a customization file be used when generating the JAX-WS and JAXB artifacts. This is accomplished using the
<binding> child element. The jwsc and wsdlc Ant tasks call Sun's
wsimport Ant task, internally.
Hopefully, this article has given you a glimpse of how easy it is to instruct the WebLogic Server 10
Web Services stack, to generate JAX-WS and JAXB artifacts. What's not so easy is creating the customization
files, which allow you to affect the artifacts' generation process. But don't worry. I've got several upcoming
articles that are completely devoted to the topic of creating customization files.
References
The following links provide additional information on things discussed in this article:
Mike Wooten is a Sr. Principal Solutions Engineer in BEA's prestigious
TSG (Technical Solutions Group). His waking hours are usually spent
helping BEA customers turn their abstract technical notions/concepts,
into revenue-generating solutions that exceed the capabilties offered by
their competitors.