Using JAX-WS and JAXB with WebLogic Server 10
by Mike Wooten
09/26/2007
Abstract
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 Glassfishwsimport
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'stype="JAXWS"
attribute to generate JAXB artifacts. Thejwsc
Ant task has a<binding>
child element for specifying the JAXB binding customization file to use. -
Start from WSDL This 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 Glassfishwsimport
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'stype="JAXWS"
attribute to generate JAXB artifacts. Thewsdlc
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://www.oracle.com/webfolder/technetwork/jsc/xml/ns/jaxws/index.html
and http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/jaxb/index.html
namespaces.
The JAX-WS customization file for this DataStagingService
Web service is pretty small, so I've included it here:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings
wsdlLocation="DataStagingService2.wsdl"
>
<bindings
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
node="wsdl:definitions"
>
<package name="services.datastaging">
<jxb:javadoc>
<![CDATA[<body>Package level documentation for generated
package services.datastaging.</body>]]>
</jxb:javadoc>
</package>
<jxb:schemaBindings>
<jxb:package name="com.acmeworld.irad.services.datastaging"/>
</jxb:schemaBindings>
</bindings>
</bindings>
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.
The next listing contains the XML Schema used in the WSDL, for the DataStagingService
Web service:
<xs:schema
targetNamespace="http://services.irad.acmeworld.com/datastaging"
xmlns:tns="http://services.irad.acmeworld.com/datastaging"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<xs:complexType name="DataStaging">
<xs:sequence>
<xs:element name="inputURIs">
<xs:complexType>
<xs:sequence>
<xs:element name="inputURI" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="uri" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="DataStagingResponse">
<xs:sequence>
<xs:element name="outputURIs">
<xs:complexType>
<xs:sequence>
<xs:element name="outputURI" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="uri" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="dataStaging" type="tns:DataStaging"/>
<xs:element name="dataStagingResponse" type="tns:DataStagingResponse"/>
</xs:schema>
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.
<path id="jaxws.classpath">
<fileset dir="${bea.home}/modules">
<include name="javax.xml.stream_1.0.0.0.jar"/>
<include name="javax.jws_2.0.jar"/>
<include name="javax.xml.bind_2.0.jar"/>
<include name="javax.xml.ws_2.0.jar"/>
<include name="javax.xml.soap_1.3.0.0.jar"/>
<include name="javax.activation_1.1.jar"/>
<include name="glassfish.jaxws.rt_2.0.1.jar"/>
<include name="glassfish.jaxb_2.0.5.jar"/>
<include name="glassfish.jaxws.saaj.impl_2.0.1.jar"/>
<include name="glassfish.jaxws.tools_2.0.1.jar"/>
</fileset>
</path>
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.
<target name="run-wsdlc" depends="clean">
<taskdef name="wsdlc" classname="weblogic.wsee.tools.anttasks.WsdlcTask"
classpathref="compile.classpath" />
<property name="client.binding" value="custom-client.xjb"/>
<wsdlc
type="JAXWS"
srcWsdl="etc/${wsdl.file.name}.wsdl"
destJwsDir="WebContent/WEB-INF/lib"
destImplDir="${src.dir}"
explode="false"
verbose="${verbose}"
debug="${debug}"
failonerror="true">
<binding dir="etc" includes="${client.binding}"/>
<classpath>
<path refid="compile.classpath"/>
</classpath>
</wsdlc>
;/target>
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<datastaging.inputuris.inputuri> 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<datastaging.inputuris> 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.