EJB 3.1 and Web Services

 

Support for web services in EJB 3.1 is based on the Java API for XML-based Web Services (JAX-WS) 2.1 specification, as well its predecessor, the Java API for XML-based RPC (JAX-RPC) 1.1. The name was changed primarily to avoid the common misconception that web services are only about RPC. Other specifications included in EJB 3.1 are the SOAP with Attachments API for Java (SAAJ) and the Java API for XML Registries (JAXR). JAX-WS and JAX-RPC are similar to RMI and CORBA, except they use the SOAP protocol; SAAJ is an API for manipulating the structure of a SOAP message; and JAXR allows you to access web services registries, usually UDDI.

In order to cover Java EE web services comprehensively, we would need another 500 pages. Since you’ll need to lift this topic to read it, we wrote a lighter approach to the subject. This topic provides you with an introduction to both JAX-WS and JAX-RPC, but you should not consider it a comprehensive guide to the APIs.

The main purpose of a web services API is to bridge Java components with the standard web services protocols. Unlike other distributed technologies, web services were designed to be very flexible and very extendable. Although this makes the technology more open and more adaptable, it also makes transparency harder to achieve. A good web services API will go to great lengths to achieve transparency. The process of invoking and defining a web service in Java should be as close as possible to invoking and defining a normal object in Java. Both JAX-RPC and JAX-WS attempt to achieve this goal, although we think you will see that JAX-WS does a much better job. We will start with the aging JAX-RPC specification and then move into the newer JAX-WS API.


Accessing Web Services with JAX-RPC

JAX-RPC provides a client-side programming model that allows you to access web services on other platforms from your EJBs. In other words, by using JAX-RPC, EJBs can access web services across the network hosted on both Java and non-Java platforms (Perl, .NET, C++, and so on). There are three APIs for accessing web services: generated stubs, dynamic proxies, and the Dynamic Invocation Interface (DII). When JAX-RPC is accessed from a Java EE/EJB 3.1 environment, the decision to use a dynamic proxy or a stub is up to the specific container on which you are running. In this case, however, a dynamic proxy will most likely be used, because a stub is not portable between Java EE platforms.

A dynamic proxy is very much like the classic Java RMI or CORBA programming model, where the client accesses a remote service via a remote interface implemented by a network stub. The stub translates calls made on the remote interface into network messages that are sent to the remote service. It’s similar to using an EJB remote reference; however, the protocol is SOAP over HTTP rather than CORBA IIOP. Figure 21-1 illustrates the remote execution loop executed with a JAX-RPC dynamic proxy.

The JAX-RPC RMI loop

Figure 21-1. The JAX-RPC RMI loop

The execution loop in JAX-RPC is the same as any other RMI loop. In Step 1, the client invokes a method on the JAX-RPC proxy that implements the service endpoint interface. The method invocation is transformed into a SOAP message that is sent to the server in Step 2. In Step 3, the web service processes the request and sends the results back as a SOAP response message in Step 4. In Step 5, the SOAP response message is transformed into either a return value or an exception (if it was a SOAP fault) and is then returned to the client.

Generating JAX-RPC Artifacts from WSDL

The primary interface that describes a JAX-RPC web service is called a service endpoint interface. A JAX-RPC-compliant compiler generates the endpoint interface from a WSDL <portType> definition. This interface, when combined with WSDL <binding> and <port> definitions, is used to create the dynamic proxy at deploy time. The organization that hosts the web service provides the WSDL document.

Imagine that Titan Cruises subcontracts a company, Charge-It Inc., to process payments made by customers using credit cards. Charge-It runs a system based on .NET and exposes its credit card processing application to clients via a web service. A WSDL document describes the web service. The WSDL document for Charge-It’s web service looks like this:

tmp986_thumb2_thumb2

The endpoint interface is based on the WSDL <portType> and its corresponding <message> definitions. Based on these definitions, a JAX-RPC compiler would generate the following interface:

tmp987_thumb_thumbtmp988_thumb_thumb

An endpoint interface is a plain Java interface that extends the java.rmi.Remote interface. All methods on the service endpoint interface must throw RemoteException, although the bean implementation class is not required to. Application exceptions can be thrown from any business method. The interface name, method names, parameters, and exceptions are derived from the WSDL document. Figure 21-2 shows the mapping between the <portType> and <message> definitions and the endpoint interface.

Mapping a WSDL <portType> to a JAX-RPC endpoint interface

Figure 21-2. Mapping a WSDL <portType> to a JAX-RPC endpoint interface

The name of the endpoint interface comes from the name of the <portType>, which is Processor. The methods defined by the endpoint interface are derived from the <operation> elements declared by the WSDL <portType>. In this case, there is one <operation> element, which maps a single method: charge(). The parameters of the charge() method are derived from the <operation> element’s input message. For each <part> element of the input message, there will be a corresponding parameter in the charge() method. The output message, in this case, declares a single <part> element, which maps to the return type of the charge() method.

The JAX-RPC specification defines an exact mapping between many of the XML Schema built-in types and Java. This is how the XML Schema types declared by the WSDL <part> elements are mapped to the parameters and the return type of an end-point method. Table 21-1 shows the mapping between XML Schema built-in types and Java primitives and classes.

Table 21-1. XML Schema built-in types and their corresponding Java types

XML Schema built-in type

Java type

xsd:byte

Byte

xsd:Boolean

Boolean

xsd:short

Short

xsd:int

Int

xsd:long

Long

xsd:float

float

xsd:double

Double

xsd:string

java.lang.String

xsd:dateTime

java.util.Calendar

xsd:integer

java.math.BigInteger

xsd:decimal

java.math.BigDecimal

xsd:QName

java.xml.namespace.QName

xsd:base64Binary

byte []

JAX-RPC also maps nillable types (types that can be null), based on XML Schema built-in types, to Java primitive wrappers. For example, a nillable xsd:int type would map to a java.lang.Integer type, and a nillable xsd:double would map to a java.lang.Double type.

In addition, JAX-RPC defines a mapping between complex types defined in the WSDL <types> element and Java bean classes.

When a service is deployed, the proxy, which implements the endpoint interface, is generated from the <binding> and <port> definitions. The JAX-RPC proxy translates the messaging style specified by the <binding> definition into a marshaling algorithm for converting method calls made on the endpoint stub into SOAP request and reply messages. Charge-It’s WSDL document defines the following <binding> element:

tmp9810_thumb_thumbtmp9811_thumb2

According to the <binding> element, the web service employs RPC/Literal SOAP 1.1 messages with a request-response-style operation. The proxy is responsible for converting method calls made on the endpoint interface into SOAP messages that are sent to the web service. It’s also responsible for converting SOAP response messages sent back to the stub into a return value—or, if it’s a SOAP fault message, into an exception thrown by the endpoint method.

The proxy also takes into consideration the <port> definition, which declares the Internet address where the web service is located. The Charge-It WSDL document defines the following <port> element:

tmp9812_thumb_thumb

The address attribute (http://www.charge-it.com/ProcessorService) specifies the URL with which the proxy will exchange SOAP messages. Figure 21-1, shown earlier, illustrates how the processor endpoint interface and stub are used to access the Charge-It credit card processing web service.

In addition to the service endpoint interface, the JAX-RPC compiler also creates a service interface, which is used to get an instance of the proxy at runtime. The service interface is based on the <service> element of the WSDL document. Here’s the definition of the ProcessorService interface generated from Charge-It’s WSDL document:

tmp9813_thumb_thumb

The getProcessorPort() method returns a proxy that is ready to invoke methods on the web service. The getProcessPortAddress() method returns the URL that the proxy accesses by default. The getProcessorPort(URL) method allows you to create an end-point stub that accesses a different URL than the default defined in the WSDL document.

Calling a Service from an EJB

As with other resources (JDBC, JMS, and so on), the generated JAX-RPC service can be injected directly into a field or setter method of the bean class. It can also be bound to a specific namespace in the JNDI ENC at deployment time. The service can then obtain the proxy, as described in the previous section.

To illustrate how EJBs use a service, we will modify the Passage() method of a fictitious TravelAgentBean. The TravelAgent EJB will use Charge-It’s Processor web service. We could look up the service directly using JNDI, but injection will save us the extra step. The following code shows the changes to the TravelAgentBean class:

tmp9814_thumb1_thumb1tmp9815_thumb2

ProcessorService is injected directly into the processorService field on the bean class. From this field, we can obtain the proxy object that implements the service endpoint interface. You will see in the next section how to configure an XML deployment descriptor to populate the field.

Invoking this proxy within a transactional business process such as Passage() presents a few problems of which you should be aware. If the proxy encounters a networking problem or SOAP processing error, it throws a RemoteException, which is caught and rethrown as an EJBException, causing the entire transaction to roll back. However, if an error occurs after the web service has executed but before the EJB method successfully returns, a partial rollback occurs; the reservation is rolled back, but the charge made using the Charge-It web service is not. Invocations on web services do not participate in the caller’s transaction context!

The <service-ref> Deployment Element

We still need to specify where and how this web service reference is defined. To do this we need a <service-ref> element in our EJB deployment descriptor. This XML element binds a JAX-RPC service to the JNDI ENC and injects it into the processorService field of our bean class. EJB XML is allowed to be a partial deployment descriptor. This means that we do not have to define every single piece of metadata in XML just because we want to inject a web service into our bean class. The partial XML deployment descriptor of the TravelAgent EJB declares a <service-ref> element that looks like this:

tmp9816_thumb1_thumbtmp9817_thumb_thumb

The <service-ref-name> element declares the name of the JAX-RPC service in the JNDI ENC—it’s always relative to the java:comp/env context. The <service-interface> element identifies the JAX-RPC service interface, which is implemented by a JAX-RPC service object. The <wsdl-file> identifies the location of the WSDL document that describes the Charge-It web service. The WSDL document must be packaged in the same EJB-JAR file as the EJB that is making the web service call, whether you are using a <service-ref> element or an annotation to inject your web service. The path is always relative to the root of the EJB-JAR file. In this case, a copy of the Charge-It WSDL document, ChargeItProcessor.wsdl, is stored in the META-INF directory of the EJB-JAR file. The <jaxrpc-mapping-file> element identifies the location of the JAX-RPC mapping file relative to the root of the EJB-JAR file. In this case, it’s also located in the META-INF directory. (The JAX-RPC mapping file is an additional deployment file that helps the EJB container to understand the mapping between the WSDL document and the service endpoint interfaces.) The <service-qname> element identifies the fully qualified XML name of the WSDL <service> definition to which this reference pertains. The qualified service name is relative to the WSDL document identified by the <wsdl-file> element. The <mapped-named> element is a vendor-specific identifier that can map to a global registry of the application server (usually the global JNDI). The <injection-target> element is used to tell the EJB container to inject an instance of ProcessorService into the processorService field of the TravelAgentBean class.

The JAX-RPC Mapping File

A JAX-RPC service or client in a Java EE environment must have a JAX-RPC mapping file. The mapping file format is defined in the “Implementing Enterprise Web Services” (JSR-109) specification. There are many possible ways to map or bind Java to WSDL, and WSDL to Java. This can cause portability problems between different JAX-RPC implementations, since they may bind Java and WSDL in different ways. The JAX-RPC mapping file addresses this problem by configuring the specific details for how binding is supposed to occur. This allows for a service and a client to be portable across different Java EE implementations. The mapping file for the ChargeItProcessor.wsdl document follows:

tmp9818_thumb_thumb

tmp9819_thumb2_thumb1

tmp9820_thumb_thumb

As you can see, the service interface is mapped to a WSDL <service> element, the endpoint interface is mapped to a WSDL <portType>, each method is mapped to a WSDL <operation>, and every parameter and return value is mapped to a specific WSDL <part> of a specific WSDL <message> definition.

The complete JAX-RPC mapping file is too complicated to discuss in detail. Don’t worry, though; you normally don’t write these by hand. A Java EE implementation will provide tools to generate these files for you. Also, the JAX-RPC mapping file is no longer used in JAX-WS. We will discuss how it handles binding in the section “Using JAX-WS” on page 396.

Defining a Web Service with JAX-RPC

Java EE provides two different programming models for defining a JAX-RPC web service: the web container model (or servlet model) and the EJB container model. Given that this topic is about EJB 3.1, we assume you are more interested in the EJB model.

The core component in the EJB model is called an EJB endpoint. An EJB endpoint is a stateless session bean that is exposed as a web service. In addition to the remote and local component interfaces, there is another component interface, called the service endpoint interface. The service endpoint interface defines the abstract web services contract that the EJB endpoint provides to a web services client.

Because an EJB endpoint is simply a SOAP-accessible stateless session bean, it has the same advantages as other EJBs. An EJB endpoint runs in the same EJB container that automatically manages transactions and security, and provides access to other EJBs and resources via injection or the JNDI ENC.

The WSDL Document

Every EJB endpoint must have a WSDL document that describes the web service. You can create this document by hand, or you can use the tools provided by your Java EE vendor to generate it. The <portType> declared by the WSDL document must be aligned with the endpoint interface of the web service. In other words, the mapping between the WSDL <portType> and the endpoint interface must be correct according to the JAX-RPC specification. One way to ensure this is to create the WSDL document first, and then use it to generate the service endpoint interface:

tmp9821_thumb2_thumb1tmp9822_thumb1_thumb1

The Service Endpoint Interface

The process for generating a service endpoint interface for an EJB endpoint is identical to the process we used to generate a JAX-RPC client. The JAX-RPC compiler generates it from the <portType> and <message> definitions (and <types>, if present). The resulting interface looks like the following:

tmp9823_thumb1_thumb1

Alternatively, you can start from Java by writing the service endpoint interface by hand. You can then generate the WSDL and the JAX-RPC mapping file from this interface. Refer to Table 21-1, earlier in this topic, to determine the schema types that will be mapped from the Java parameters in each method.

The Stateless Bean Class

The bean class defined for the TravelAgent endpoint must implement the methods defined by the endpoint interface. As with remote and local interfaces, a stateless bean class can implement the service endpoint interface directly. Here’s the new definition for the TravelAgentBean class:

tmp9824_thumb_thumbtmp9825_thumb1_thumb1

The TravelAgentBean class is not that different from the TravelAgent EJB developed earlier in this topic (the version that uses the Charge-It credit card processing web service). The primary differences are that it responds to web service calls rather than remote or local calls, and it is a stateless session bean rather than a stateful session bean.

The Deployment Files

The TravelAgent endpoint requires three deployment files: a WSDL file, a JAX-RPC mapping file, and a webservices.xml file. In this section, we will create these files manually, although you would typically use the tools provided by your Java EE implementation to assist in this process.

The WSDL file

The WSDL file used to represent the endpoint interface must be packaged with the EJB endpoint. Normally, the WSDL document is placed in the META-INF directory of the JAR file, but it can go anywhere as long as it’s in the same JAR file as the EJB endpoint.

The JAX-RPC mapping file

EJB endpoints, like JAX-RPC service references, require you to define a JAX-RPC mapping file. The mapping file can have any name, but it should be descriptive, and the file type should be XML. It’s common to name this file jaxrpc-mapping.xml or travel-agent_mapping.xml, or something along those lines. We covered the JAX-RPC mapping file in “The JAX-RPC Mapping File” on page 389.

The webservices.xml file

The webservices.xml file is the baling wire that ties the separate deployment files together. It defines the relationships between the stateless session bean, the WSDL file, and the JAX-RPC mapping file:

tmp9826_thumb1_thumb1

The <webservice-description> element describes an EJB endpoint; there may be one or more of these elements in a single webservices.xml file.* <webservice-description-name> is a unique name assigned to the web services description. It can be anything you like. The <wsdl-file> element points to the WSDL document of the EJB endpoint. Each EJB endpoint has exactly one WSDL document, which is usually located in the META-INF directory of the EJB-JAR file. When the EJB endpoint is deployed, your deployment tool will probably provide you with the option of copying the WSDL document to some type of public URL or registry so that others can discover the web service. The <jaxrpc-mapping-file> element indicates the location of the JAX-RPC mapping file that is associated with the EJB endpoint and the WSDL document. It, too, is usually located in the META-INF directory of the EJB-JAR file.

The <port-component> element maps a stateless session bean declared in the ejb-jar.xml file to a specific <port> in the WSDL document. <port-component-name> is the logical name you assign the EJB endpoint. It can be anything. The <wsdl-port> element maps the EJB endpoint deployment information to a specific WSDL <port> element in the WSDL document. <service-endpoint-interface> is the fully qualified name of the endpoint interface; it must be the same interface declared by the <service-endpoint> element for the EJB in the ejb-jar.xml file. <service-impl-bean> and its <ejb-link> element link the <port-component> to a specific EJB. The value of <ejb-link> must match the value of the EJB name, which is TravelAgentBean in this example.

Using JAX-WS

The WSDL, JAX-RPC mapping, and webservices.xml files sure are a lot of things to define just to expose your stateless EJB as a web service. It should be easier to publish an EJB as a web service—and it is. One of the goals of the JAX-WS specification was to make the JAX-RPC API and deployment model easier to use. To this end, the specification provides an extensive set of annotations, most of which are based on JSR-181 (“Web Services Metadata for the Java Platform”). These annotations make it much simpler to define a web service. Keeping with the spirit of EJB 3.1, all JAX-WS annotations have reasonable defaults. In the following example, it takes nothing more than adding two annotations to transform a stateless EJB into a web service:

tmp9827_thumb1_thumb1

The @WebService Annotation

The main annotation for defining a web service is @javax.jws.WebService. This annotation must be placed on the stateless session bean implementation class in order to expose it as a web service:

tmp9828_thumb_thumbtmp9829_thumb_thumb

The name() attribute is the name of the web service, and it is used as the name of the portType when mapped to WSDL. This defaults to the short name of the Java class or Java interface to which you are applying it. The targetNamespace() attribute specifies the XML namespace used for the WSDL and XML elements that are generated from this annotation. The default value is generated from the package name of the annotated type. The wsdlLocation() attribute defines the URL of the WSDL document that represents this web service. You need this attribute only if you are mapping your service to a preexisting WSDL document. The endpointInterface() attribute is used to externalize the contract of the web service by specifying that contract in the form of a Java interface. We’ll talk more about this option later. The portName() attribute specifies which WSDL port you will use. In most cases, you can use the default values for each of these attributes.

The @WebMethod Annotation

If a stateless session bean is annotated with @java.jws.WebService, and it contains no methods that are annotated with @javax.jws.WebMethod, then all methods are made available to the web service. Otherwise, only those methods that are annotated with @javax.jws.WebMethod will be made available. This is an important feature because web services tend to be coarser-grained than a standard EJB. Also, it is generally considered good design practice to reduce dependencies between modules. The @javax.jws.Web Method annotation also offers attributes for customizing the generated WSDL:

tmp9830_thumb_thumb

The operationName() attribute is used to define the WSDL operation that the annotated method implements. If it is not specified, the literal Java method name is used. The action() attribute is used to set the SOAPAction hint that corresponds with this operation. This hint allows a service endpoint to determine the destination by simply looking at the SOAPAction HTTP header instead of analyzing the contents of the SOAP message body. This has the potential for a slight performance increase, although it depends on the Java EE implementation you are using.

The @SOAPBinding Annotation

The following example demonstrates setting the operation name for a Java method:

tmp9831_thumb1_thumb1

This will result in the following WSDL portType definition:

tmp9832_thumb_thumb

We discussed the web services styles supported in EJB 3.1. You can customize the web services style that the EJB endpoint uses with the @javax.jws.soap.SOAPBinding annotation:

tmp9833_thumb1_thumb1

Table 21-2 describes the supported attribute value combinations. It is important to note that the use() attribute must always be set to LITERAL. ENCODED refers to SOAP encoding, which has been disallowed by the WS-I Basic Profile 1.1. Furthermore, an EJB implementation is not required to support it. If this annotation is not specified, the default style is Document/Literal Wrapped.

Table 21-2. @SOAPBinding behavior

Style

Use

Parameter style

Description

RPC

LITERAL

N/A

Each parameter is mapped to a wsdl:part, which is mapped to a schema type definition.

DOCUMENT

LITERAL

BARE

Only one parameter is allowed, and that parameter is mapped to a root schema element that fully defines the content of the message.

DOCUMENT

LITERAL

WRAPPED

All parameters are wrapped in a root schema element with the same name as the operation to which they belong.

The @WebParam Annotation

The @javax.jws.WebParam annotation allows you to control the WSDL that is generated for a Java method annotated with @javax.jws.WebMethod:

tmp9834_thumb_thumb

If the style is RPC/Literal, the name() attribute sets the wsdl:part name. Otherwise, it sets the XML local name of the element within the schema document that corresponds to the annotated parameter. If it is not specified, the default value is computed in the form of argN, where N is the 0-based position of the parameter in the method signature. The targetNamespace() attribute is used only if the style is Document/Literal or the parameter is a header. It sets the targetNamespace of the schema definition that contains the element. The header() attribute is used to indicate that the parameter should be put in a SOAP header rather than in the SOAP body. The mode() attribute is used to indicate whether the parameter is to be used for input, output, or both. Due to Java semantics, if a parameter is used for output, it must be wrapped using a special holder type. The following example shows the use of a JAX-WS holder on an RPC-style service:

tmp9835_thumb_thumbtmp9836_thumb1_thumb1

The @WebResult Annotation

This @javax.jws.WebResult annotation provides the same, although somewhat reduced, functionality for return values that @javax.jws.WebParam provides for method parameters:

tmp9837_thumb1_thumb1

The attributes behave the same as they do in @javax.jws.WebParam, with the exception of the default value for name(). If the name() attribute is not specified, and the style is Document/Literal bare, then its value will be the WSDL operation name concatenated with “Response”. For all other styles, the default is “return”. The following example demonstrates the use of this annotation:

tmp9838_thumb_thumb

The @OneWay Annotation

The @javax.jws.OneWay annotation is used to declare that the corresponding web services operation will return an empty message. This allows the server and the client to optimize the operation by performing the method invocation asynchronously. Whether the method is actually executed asynchronously is determined by the Java EE implementation. The resulting WSDL for a one-way operation will not have an <output> tag.

Separating the Web Services Contract

Up to this point, we have been defining everything within the EJB implementation class. An alternative approach is to use the endpointInterface() attribute of the @javax.jws.WebService annotation. The web services contract can then be maintained in an external Java interface. With this methodology, the only required annotation on the endpoint interface is @javax.jws.WebService. All other annotations are optional. Unlike the previous approach of keeping everything within the EJB implementation, all methods in the interface are exposed in the web service. Technically, the EJB implementation does not have to implement this interface, although there is no reason not to. We can modify the TravelAgentBean example to utilize this approach by first extracting the desired web methods:

tmp9839_thumb_thumb

This produces the following relevant WSDL sections:

tmp9840_thumb1_thumb

tmp9841_thumb_thumbtmp9842_thumb_thumb

The implementation bean then references the endpoint interface from the @javax.jws.WebService annotation:

tmp9843_thumb2_thumb

The Service Class

Similar to the JAX-RPC client methodology we discussed earlier, JAX-WS contains a service class that the JAX-WS client uses to communicate with a web service. The service class must extend javax.xml.ws.Service and provide a method to retrieve the service endpoint interface. It should also use the @javax.xml.ws.WebServiceClient annotation to define the name, namespace, and WSDL location of the service. The @javax.xml.ws.WebEndpoint annotation is necessary to resolve for which WSDL <port> to return a proxy. The following is an example Service class that communicates with the Charge-It web service:

tmp9844_thumb1_thumb

The Service Endpoint Interface

We discussed a JAX-WS service endpoint interface in “Separating the Web Services Contract” on page 401. Our client can use the same interface. This means that the client uses all of the annotations we defined for the server side. However, remember that you are not limited to just talking to JAX-WS web services. A web service can be running on any platform in any language. So, in those scenarios, you will not reuse the service endpoint interface but will instead use a tool to generate one for you. However, we will go ahead and do this by hand:

tmp9845_thumb1_thumb

The @WebServiceRef Annotation

In addition to the <service-ref> XML tag in ejb-jar.xml, a JAX-WS client can use the @javax.xml.ws.WebServiceRef annotation to reference either a service interface or a service endpoint interface directly:

tmp9846_thumb_thumb

The name() attribute defines how the web service will be bound into the JNDI ENC. The wsdlLocation() attribute specifies the URL where the WSDL file lives in the EJB-JAR. HTTP URLs are allowed. If not specified, the value for this attribute will be pulled from the service class, provided it is annotated with the @javax.xml.ws.WebService Client annotation.

The mappedName() attribute is a vendor-specific global identifier for the web service. Consult your vendor documentation to determine whether you need this attribute.

The type() and value() attributes are used to determine whether to inject a service class or service endpoint interface into a field or property. In order to inject a service endpoint interface, value() must be set to the service interface. The type() attribute can then refer to the service endpoint interface that will be injected. This does not have to be specified if the container can infer that information from the field type:

tmp9847_thumb_thumb

Let’s modify our TravelAgent EJB bean class to use this annotation:

tmp9848_thumb1_thumb1

tmp9849_thumb_thumb

In order to inject a service interface, both the value() and type() attributes can be set to the service interface class; otherwise, it can be inferred from the type:

tmp9850_thumb_thumb

In this example, the annotation will cause a dynamic proxy that implements the Processor interface to be injected into the processor field. Because we are injecting a service endpoint interface directly into the field, the value() attribute must be employed to specify which JAX-WS service class will be used to create the endpoint.

You can also override attributes of this annotation with the <service-ref> tag we covered earlier.

Other Annotations and APIs

JAX-WS also provides a few more annotations for advanced customization, as well as some additional client APIs for invoking services dynamically and supporting some of the latest WS-* specifications. However, this topic does not expand on those topics because they would detract from our focus—building Enterprise Java Beans. For more information on them, please see the relevant specifications.

JAXB

The Java Architecture for XML Binding, or JAXB for short, is a framework for mapping XML content to and from Java objects. Mapping is performed in accordance to annotations specified on the relevant Java class. These annotations are either written by hand or alternatively generated from a schema file. Since a custom marshaling engine is created from the annotations, schema parsing is not necessary. Also, the generated engine is reused across multiple requests, which makes it ideal for web services. For these reasons, JAX-WS uses JAXB for all complex type processing.

Following the schema first methodology, we can construct a simple address type:

tmp9851_thumb1_thumb1

This can then be passed to the JAXB xjc tool to generate a Java object that represents this custom type:

tmp9852_thumb_thumb

tmp9853_thumb1_thumb1

The resulting Address class can now be modified, or added to any JAX-WS service endpoint as described earlier. The resulting service will use a complex type according to the schema, and the WSDL generated from the service endpoint will include an equivalent schema to the one passed to xjc.

tmp9854_thumb_thumb

When passed to a JAX-WS tool, such as the JDK6-provided wsgen, the following custom type appears (as expected):

tmp9855_thumb1_thumb

Taking JAXB Further

The previous examples just demonstrate the basic capabilities of JAXB. The framework has facilities for much more advanced cases, and supports almost all of XML Schema fairly well without customization. There are, however, some limitations. These are mostly caused by the fact that XML Schema supports concepts with no clear mapping to the Java language (e.g., unions, restrictions). In such cases, specialized annotations may need to be added. See the official JAXB specification and/or javadoc for more information on how it addresses these issues.

Next post:

Previous post: