The Java EE 5 Tutorial

Part III Web Services

Part Three explores web services.

Chapter 16 Building Web Services with JAX-WS

JAX-WS stands for Java API for XML Web Services. JAX-WS is a technology for building web services and clients that communicate using XML. JAX-WS allows developers to write message-oriented as well as RPC-oriented web services.

In JAX-WS, a web service operation invocation is represented by an XML-based protocol such as SOAP. The SOAP specification defines the envelope structure, encoding rules, and conventions for representing web service invocations and responses. These calls and responses are transmitted as SOAP messages (XML files) over HTTP.

Although SOAP messages are complex, the JAX-WS API hides this complexity from the application developer. On the server side, the developer specifies the web service operations by defining methods in an interface written in the Java programming language. The developer also codes one or more classes that implement those methods. Client programs are also easy to code. A client creates a proxy (a local object representing the service) and then simply invokes methods on the proxy. With JAX-WS, the developer does not generate or parse SOAP messages. It is the JAX-WS runtime system that converts the API calls and responses to and from SOAP messages.

With JAX-WS, clients and web services have a big advantage: the platform independence of the Java programming language. In addition, JAX-WS is not restrictive: a JAX-WS client can access a web service that is not running on the Java platform, and vice versa. This flexibility is possible because JAX-WS uses technologies defined by the World Wide Web Consortium (W3C): HTTP, SOAP, and the Web Service Description Language (WSDL). WSDL specifies an XML format for describing a service as a set of endpoints operating on messages.

Setting the Port

Several files in the JAX-WS examples depend on the port that you specified when you installed the Application Server. The tutorial examples assume that the server runs on the default port, 8080. If you have changed the port, you must update the port number in the following file before building and running the JAX-WS examples:


tut-install/javaeetutorial5/examples/jaxws/simpleclient/src/java/simpleclient/HelloClient.java

Creating a Simple Web Service and Client with JAX-WS

This section shows how to build and deploy a simple web service and client. The source code for the service is in tut-install/javaeetutorial5/examples/jaxws/helloservice/ and the client is in tut-install/javaeetutorial5/examples/jaxws/simpleclient/.

Figure 16–1 illustrates how JAX-WS technology manages communication between a web service and client.

Figure 16–1 Communication between a JAX-WS Web Service and a Client

Diagram showing a client and web service communicating
through a SOAP message.

The starting point for developing a JAX-WS web service is a Java class annotated with the javax.jws.WebService annotation. The @WebService annotation defines the class as a web service endpoint.

A service endpoint interface or service endpoint implementation (SEI) is a Java interface or class, respectively, that declares the methods that a client can invoke on the service. An interface is not required when building a JAX-WS endpoint. The web service implementation class implicitly defines an SEI.

You may specify an explicit interface by adding the endpointInterface element to the @WebService annotation in the implementation class. You must then provide an interface that defines the public methods made available in the endpoint implementation class.

You use the endpoint implementation class and the wsgen tool to generate the web service artifacts that connect a web service client to the JAX-WS runtime. For reference documentation on wsgen, see the Sun Java System Application Server 9.1 Reference Manual.

Together, the wsgen tool and the Application Server provide the Application Server’s implementation of JAX-WS.

    These are the basic steps for creating the web service and client:

  1. Code the implementation class.

  2. Compile the implementation class.

  3. Use wsgen to generate the artifacts required to deploy the service.

  4. Package the files into a WAR file.

  5. Deploy the WAR file. The web service artifacts (which are used to communicate with clients) are generated by the Application Server during deployment.

  6. Code the client class.

  7. Use wsimport to generate and compile the web service artifacts needed to connect to the service.

  8. Compile the client class.

  9. Run the client.

The sections that follow cover these steps in greater detail.

Requirements of a JAX-WS Endpoint

JAX-WS endpoints must follow these requirements:

Coding the Service Endpoint Implementation Class

In this example, the implementation class, Hello, is annotated as a web service endpoint using the @WebService annotation. Hello declares a single method named sayHello, annotated with the @WebMethod annotation. @WebMethod exposes the annotated method to web service clients. sayHello returns a greeting to the client, using the name passed to sayHello to compose the greeting. The implementation class also must define a default, public, no-argument constructor.

package helloservice.endpoint;

import javax.jws.WebService;

@WebService
public class Hello {
    private String message = new String("Hello, ");

    public void Hello() {}

    @WebMethod
    public String sayHello(String name) {
        return message + name + ".";
    }
}

Building, Packaging, and Deploying the Service

You can build, package, and deploy the helloservice application using either NetBeans IDE or ant.

Building, Packaging, and Deploying the Service Using NetBeans IDE

Follow these instructions to build, package, and deploy the helloservice example to your Application Server instance using the NetBeans IDE IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxws/.

  3. Select the helloservice folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the helloservice project and select Undeploy and Deploy.

This builds and packages to application into helloservice.war, located in tut-install/javaeetutorial5/examples/jaxws/helloservice/dist/, and deploys this WAR file to your Application Server instance.

Building, Packaging, and Deploying the Service Using Ant

To build and package helloservice using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxws/helloservice/ directory and type the following:


ant

This command calls the default target, which builds and packages the application into an WAR file, helloservice.war, located in the dist directory.

    To deploy the helloservice example, follow these steps:

  1. In a terminal window, go to tut-install/javaeetutorial5/examples/jaxws/helloservice/.

  2. Make sure the Application Server is started.

  3. Run ant deploy.

You can view the WSDL file of the deployed service by requesting the URL http://localhost:8080/helloservice/hello?WSDL in a web browser. Now you are ready to create a client that accesses this service.

Undeploying the Service

At this point in the tutorial, do not undeploy the service. When you are finished with this example, you can undeploy the service by typing this command:


ant undeploy

The all Task

As a convenience, the all task will build, package, and deploy the application. To do this, enter the following command:


ant all

Testing the Service without a Client

    The Application Server Admin Console allows you to test the methods of a web service endpoint. To test the sayHello method of HelloService, do the following:

  1. Open the Admin Console by typing the following URL in a web browser:


    http://localhost:4848/
  2. Enter the admin user name and password to log in to the Admin Console.

  3. Click Web Services in the left pane of the Admin Console.

  4. Click Hello.

  5. Click Test.

  6. Under Methods, enter a name as the parameter to the sayHello method.

  7. Click the sayHello button.

    This will take you to the sayHello Method invocation page.

  8. Under Method returned, you’ll see the response from the endpoint.

A Simple JAX-WS Client

HelloClient is a stand-alone Java program that accesses the sayHello method of HelloService. It makes this call through a port, a local object that acts as a proxy for the remote service. The port is created at development time by the wsimport tool, which generates JAX-WS portable artifacts based on a WSDL file.

Coding the Client

    When invoking the remote methods on the port, the client performs these steps:

  1. Uses the javax.xml.ws.WebServiceRef annotation to declare a reference to a web service. @WebServiceRef uses the wsdlLocation element to specify the URI of the deployed service’s WSDL file.

    @WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
    static HelloService service;
  2. Retrieves a proxy to the service, also known as a port, by invoking getHelloPort on the service.

    Hello port = service.getHelloPort();

    The port implements the SEI defined by the service.

  3. Invokes the port’s sayHello method, passing to the service a name.

    String response = port.sayHello(name);

Here is the full source of HelloClient, which is located in the tut-install/javaeetutorial5/examples/jaxws/simpleclient/src/java/ directory.

package simpleclient;

import javax.xml.ws.WebServiceRef;
import helloservice.endpoint.HelloService;
import helloservice.endpoint.Hello;

public class HelloClient {
    @WebServiceRef(wsdlLocation="http://localhost:8080/
            helloservice/hello?wsdl")
    static HelloService service;

    public static void main(String[] args) {
        try {
            HelloClient client = new HelloClient();
            client.doTest(args);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public void doTest(String[] args) {
        try {
            System.out.println("Retrieving the port from
                     the following service: " + service);
            Hello port = service.getHelloPort();
            System.out.println("Invoking the sayHello operation
                     on the port.");

            String name;
            if (args.length > 0) {
                name = args[0];
            } else {
                name = "No Name";
            }

            String response = port.sayHello(name);
            System.out.println(response);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

Building and Running the Client

You can build and run the simpleclient application using either NetBeans IDE or ant. To build the client, you must first have deployed helloservice, as described in Building, Packaging, and Deploying the Service.

Building and Running the Client in NetBeans IDE

    Do the following to build and run simpleclient:

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxws/.

  3. Select the simpleclient folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the simpleclient project and select Run.

You will see the output of the application client in the Output pane.

Building and Running the Client Using Ant

In a terminal navigate to tut-install/examples/jaxws/simpleclient/ and type the following command:


ant

This command calls the default target, which builds and packages the application into a JAR file, simpleclient.jar, located in the dist directory.

The run the client, type the following command:


ant run

Types Supported by JAX-WS

JAX-WS delegates the mapping of Java programming language types to and from XML definitions to JAXB. Application developers don’t need to know the details of these mappings, but they should be aware that not every class in the Java language can be used as a method parameter or return type in JAX-WS. For information on which types are supported by JAXB, see Chapter 17, Binding between XML Schema and Java Classes.

Web Services Interoperability and JAX-WS

JAX-WS 2.0 supports the Web Services Interoperability (WS-I) Basic Profile Version 1.1. The WS-I Basic Profile is a document that clarifies the SOAP 1.1 and WSDL 1.1 specifications to promote SOAP interoperability. For links related to WS-I, see Further Information about JAX-WS.

To support WS-I Basic Profile Version 1.1, the JAX-WS runtime supports doc/literal and rpc/literal encodings for services, static ports, dynamic proxies, and DII.

Further Information about JAX-WS

For more information about JAX-WS and related technologies, see:

Chapter 17 Binding between XML Schema and Java Classes

The JavaTM Architecture for XML Binding (JAXB) provides a fast and convenient way to bind between XML schemas and Java representations, making it easy for Java developers to incorporate XML data and processing functions in Java applications. As part of this process, JAXB provides methods for unmarshalling XML instance documents into Java content trees, and then marshalling Java content trees back into XML instance documents. JAXB also provides a way to generate XML schema from Java objects.

JAXB 2.0 includes several important improvements to JAXB 1.0:

This chapter describes the JAXB architecture, functions, and core concepts, and provides examples with step-by-step procedures for using JAXB.

JAXB Architecture

This section describes the components and interactions in the JAXB processing model.

Architectural Overview

Figure 17–1 shows the components that make up a JAXB implementation.

Figure 17–1 JAXB Architectural Overview

Diagram of JAXB architecture, showing Schema on left,
Schema Generator and Schema Compiler in the middle, and Application Code on
the right.

A JAXB implementation consists of the following architectural components:

The JAXB Binding Process

Figure 17–2 shows what occurs during the JAXB binding process.

Figure 17–2 Steps in the JAXB Binding Process

Diagram of the JAXB Binding Process: Schema, JAXB mapped
classes, Document, and Objects

    The general steps in the JAXB data binding process are:

  1. Generate classes: An XML schema is used as input to the JAXB binding compiler to generate JAXB classes based on that schema.

  2. Compile classes: All of the generated classes, source files, and application code must be compiled.

  3. Unmarshal: XML documents written according to the constraints in the source schema are unmarshalled by the JAXB binding framework. Note that JAXB also supports unmarshalling XML data from sources other than files/documents, such as DOM nodes, string buffers, SAX Sources, and so forth.

  4. Generate content tree: The unmarshalling process generates a content tree of data objects instantiated from the generated JAXB classes; this content tree represents the structure and content of the source XML documents.

  5. Validate (optional): The unmarshalling process optionally involves validation of the source XML documents before generating the content tree. Note that if you modify the content tree in Step 6, below, you can also use the JAXB Validate operation to validate the changes before marshalling the content back to an XML document.

  6. Process content: The client application can modify the XML data represented by the Java content tree by means of interfaces generated by the binding compiler.

  7. Marshal: The processed content tree is marshalled out to one or more XML output documents. The content may be validated before marshalling.

More about Unmarshalling

Unmarshalling provides a client application the ability to convert XML data into JAXB-derived Java objects.

More about Marshalling

Marshalling provides a client application the ability to convert a JAXB-derived Java object tree back into XML data.

By default, the Marshaller uses UTF-8 encoding when generating XML data.

Client applications are not required to validate the Java content tree before marshalling. There is also no requirement that the Java content tree be valid with respect to its original schema to marshal it back into XML data.

More about Validation

Validation is the process of verifying that an XML document meets all the constraints expressed in the schema. JAXB 1.0 provided validation at unmarshal time and also enabled on-demand validation on a JAXB content tree. JAXB 2.0 only allows validation at unmarshal and marshal time. A web service processing model is to be lax in reading in data and strict on writing it out. To meet that model, validation was added to marshal time so one could confirm that they did not invalidate the XML document when modifying the document in JAXB form.

Representing XML Content

This section describes how JAXB represents XML content as Java objects.

Java Representation of XML Schema

JAXB supports the grouping of generated classes in Java packages. A package consists of the following:

Binding XML Schemas

This section describes the default XML-to-Java bindings used by JAXB. All of these bindings can be overridden on global or case-by-case levels by means of a custom binding declaration. See the JAXB Specification for complete information about the default JAXB bindings.

Simple Type Definitions

A schema component using a simple type definition typically binds to a Java property. Since there are different kinds of such schema components, the following Java property attributes (common to the schema components) include:

The rest of the Java property attributes are specified in the schema component using the simple type definition.

Default Data Type Bindings

The following sections explain the default schema-to-Java, JAXBElement, and Java-to-schema data type bindings.

Schema-to-Java Mapping

The Java language provides a richer set of data type than XML schema. Table 17–1 lists the mapping of XML data types to Java data types in JAXB.

Table 17–1 JAXB Mapping of XML Schema Built-in Data Types

XML Schema Type 

Java Data Type 

xsd:string

java.lang.String

xsd:integer

java.math.BigInteger

xsd:int

int

xsd.long

long

xsd:short

short

xsd:decimal

java.math.BigDecimal

xsd:float

float

xsd:double

double

xsd:boolean

boolean

xsd:byte

byte

xsd:QName

javax.xml.namespace.QName

xsd:dateTime

javax.xml.datatype.XMLGregorianCalendar

xsd:base64Binary

byte[]

xsd:hexBinary

byte[]

xsd:unsignedInt

long

xsd:unsignedShort

int

xsd:unsignedByte

short

xsd:time

javax.xml.datatype.XMLGregorianCalendar

xsd:date

javax.xml.datatype.XMLGregorianCalendar

xsd:g

javax.xml.datatype.XMLGregorianCalendar

xsd:anySimpleType

java.lang.Object

xsd:anySimpleType

java.lang.String

xsd:duration

javax.xml.datatype.Duration

xsd:NOTATION

javax.xml.namespace.QName

JAXBElement Object

When XML element information can not be inferred by the derived Java representation of the XML content, a JAXBElement object is provided. This object has methods for getting and setting the object name and object value.

Java-to-Schema Mapping

Table 17–2 shows the default mapping of Java classes to XML data types.

Table 17–2 JAXB Mapping of XML Data Types to Java Classes

Java Class 

XML Data Type 

java.lang.String

xs:string

java.math.BigInteger

xs:integer

java.math.BigDecimal

xs:decimal

java.util.Calendar

xs:dateTime

java.util.Date

xs:dateTime

javax.xml.namespace.QName

xs:QName

java.net.URI

xs:string

javax.xml.datatype.XMLGregorianCalendar

xs:anySimpleType

javax.xml.datatype.Duration

xs:duration

java.lang.Object

xs:anyType

java.awt.Image

xs:base64Binary

javax.activation.DataHandler

xs:base64Binary

javax.xml.transform.Source

xs:base64Binary

java.util.UUID

xs:string

Customizing Generated Classes and Java Program Elements

The following sections explain how to customize generated JAXB classes and Java program elements.

Schema-to-Java

Custom JAXB binding declarations allow you to customize your generated JAXB classes beyond the XML-specific constraints in an XML schema to include Java-specific refinements, such as class and package name mappings.

JAXB provides two ways to customize an XML schema:

Code examples that show how to customize JAXB bindings are provided later in this chapter.

Java-to-Schema

The JAXB annotations defined in the javax.xml.bind.annotations package can be used to customize Java program elements to XML schema mapping. Table 17–3 summarizes the JAXB annotations that can be used with a Java package.

Table 17–3 JAXB Annotations Associated with a Java Package

Annotation 

Description and Default Setting 

@XmlSchema

Maps a package to an XML target namespace. Default Settings: 

@XmlSchema ( 
   xmlns = {}, 
   namespace = "", 
   elementFormDefault = XmlNsForm.UNSET, 
   attributeFormDefault = XmlNsForm.UNSET
)

@XmlAccessorType

Controls default serialization of fields and properties. Default Settings: 

@XmlAccessorType (
   value = AccessType.PUBLIC_MEMBER 
)

@XmlAccessorOrder

Controls the default ordering of properties and fields mapped to XML elements. Default Settings: 

@XmlAccessorOrder (
   value = AccessorOrder.UNDEFINED
)

@XmlSchemaType

Allows a customized mapping to an XML Schema built-in type. Default Settings: 

@XmlSchemaType (
   namespace = "http://www.w3.org/2001/XMLSchema", 
   type = DEFAULT.class
)

@XmlSchemaTypes

A container annotation for defining multiple @XmlSchemaType annotations. Default Settings:

None 

Table 17–4 summarizes JAXB annotations that can be used with a Java class.

Table 17–4 JAXB Annotations Associated with a Java Class

Annotation 

Description and Default Setting 

@XmlType

Maps a Java class to a schema type. Default Settings: 

@XmlType (
   name = "##default", 
   propOrder = {""}, 
   namespace = "##default", 
   factoryClass = DEFAULT.class, 
   factoryMethod = ""
)

@XmlRootElement

Associates a global element with the schema type to which the class is mapped. Default Settings: 

@XmlRootElement (
   name = "##default", 
   namespace = "##default" 
)

Table 17–5 summarizes JAXB annotations that can be used with a Java enum type.

Table 17–5 JAXB Annotations Associated with a Java enum Type

Annotation 

Description and Default Setting 

@XmlEnum

Maps a Java type to an XML simple type. Default Settings: 

@XmlEnum ( value = String.class )

@XmlEnumValue

Maps a Java type to an XML simple type. Default Settings: 

None 

@XmlType

Maps a Java class to a schema type. Default Settings: 

@XmlType (
   name = "##default", 
   propOrder = {""}, 
   namespace = "##default", 
   factoryClass = DEFAULT.class, 
   factoryMethod = ""
)

@XmlRootElement

Associates a global element with the schema type to which the class is mapped. Default Settings: 

@XmlRootElement (
   name = "##default", 
   namespace = "##default" 
)

Table 17–6 summarizes JAXB annotations that can be used with Java properties and fields.

Table 17–6 JAXB Annotations Associated with Java Properties and Fields

Annotation 

Description and Default Setting 

@XmlElement

Maps a JavaBeans property/field to an XML element derived from a property/field name. Default Settings: 

@XmlElement (
   name = "##default", 
   nillable = false, 
   namespace = "##default", 
   type = DEFAULT.class, 
   defaultValue = "\u0000"
)

@XmlElements

A container annotation for defining multiple @XmlElement annotations. Default Settings:

None 

@XmlElementRef

Maps a JavaBeans property/field to an XML element derived from a property/field’s type. Default Settings: 

@XmlElementRef (
   name = "##default", 
   namespace = "##default", 
   type = DEFAULT.class
)

@XmlElementRefs

A container annotation for defining multiple @XmlElementRef annotations. Default Settings:

None 

@XmlElementWrapper

Generates a wrapper element around an XML representation. Typically a wrapper XML element around collections. Default Settings: 

@XmlElementWrapper (
   name = "##default", 
   namespace = "##default", 
   nillable = false
)

@XmlAnyElement

Maps a JavaBeans property to an XML infoset representation and/or JAXB element. Default Settings: 

@XmlAnyElement (
   lax = false, 
   value = W3CDomHandler.class
)

@XmlAttribute

Maps a JavaBeans property to an XML attribute. Default Settings: 

@XmlAttribute (
   name = ##default, 
   required = false, 
   namespace = "##default" 
)

@XmlAnyAttribute

Maps a JavaBeans property to a map of wildcard attributes. Default Settings: 

None 

@XmlTransient

Prevents the mapping of a JavaBeans property to an XML representation. Default Settings: 

None 

@XmlValue

Defines mapping of a class to an XML Schema complex type with a simpleContent or an XML Schema simple type. Default Settings:

None 

@XmlID

Maps a JavaBeans property to an XML ID. Default Settings: 

None 

@XmlIDREF

Maps a JavaBeans property to an XML IDREF. Default Settings: 

None 

@XmlList

Maps a property to a list simple type. Default Settings: 

None 

@XmlMixed

Marks a JavaBeans multi-valued property to support mixed content. Default Settings: 

None 

@XmlMimeType

Associates the MIME type that controls the XML representation of the property. Default Settings: 

None 

@XmlAttachmentRef

Marks a field/property that its XML form is a URI reference to mime content. Default Settings: 

None 

@XmlInlineBinaryData

Disables consideration of XOP encoding for data types that are bound to base64-encoded binary data in XML. Default Settings: 

None 

Table 17–7 summarizes the JAXB annotation that can be used with object factories.

Table 17–7 JAXB Annotations Associated with Object Factories

Annotation 

Description and Default Setting 

@XmlElementDecl

Maps a factory method to an XML element. Default Settings: 

@XmlElementDecl (
   scope = GLOBAL.class, 
   namespace = "##default", 
   substitutionHeadNamespace = "##default", 
   substitutionHeadName = ""
)

Table 17–8 summarizes JAXB annotations that can be used with adapters.

Table 17–8 JAXB Annotations Associated with Adapters

Annotation 

Description and Default Setting 

@XmlJavaTypeAdapter

Use the adapter that implements the @XmlAdapter annotation for custom marshalling. Default Settings:

@XmlJavaTypeAdapter ( type = DEFAULT.class )

@XmlJavaTypeAdapters

A container annotation for defining multiple @XmlJavaTypeAdapter annotations at the package level. Default Settings:

None 

JAXB Examples

The sections that follow provide instructions for using the example Java applications that are included in the tut-install/javaeetutorial5/examples/jaxb/ directory. These examples demonstrate and build upon key JAXB features and concepts. Follow these procedures in the order presented.

After reading this section, you should feel comfortable enough with JAXB that you can:

This chapter describes three sets of examples:

The Basic and Customize example directories contain several base files:

Table 17–9, Table 17–10, and Table 17–11 briefly describe the Basic, Customize, and Java-to-Schema JAXB examples.

Table 17–9 Basic JAXB Examples

Example Name 

Description 

Modify Marshal Example

Demonstrates how to modify a Java content tree. 

Unmarshal Validate Example

Demonstrates how to enable validation during unmarshalling. 

Table 17–10 Customize JAXB Examples

Example Name 

Description 

Customize Inline Example

Demonstrates how to customize the default JAXB bindings by using inline annotations in an XML schema. 

Datatype Converter Example

Similar to the Customize Inline example, this example illustrates alternate, more terse bindings of XML simpleType definitions to Java data types.

External Customize Example

Illustrates how to use an external binding declarations file to pass binding customizations for a read-only schema to the JAXB binding compiler. 

Table 17–11 Java-to-Schema JAXB Examples

Example Name 

Description 

Create Marshal Example

Illustrates how to marshal and unmarshal JAXB-annotated classes to XML schema. The example also shows how to enable JAXP 1.3 validation at unmarshal time using a schema file that was generated from the JAXB mapped classes. 

XmlAccessorOrder Example

Illustrates how to use the @XmlAccessorOrder and @XmlType.propOrder mapping annotations in Java classes to control the order in which XML content is marshalled/unmarshalled by a Java type.

XmlAdapter Field Example

Illustrates how to use the interface XmlAdapter and the annotation @XmlJavaTypeAdapter to provide a a custom mapping of XML content into and out of a HashMap (field) that uses an int as the key and a String as the value.

XmlAttribute Field Example

Illustrates how to use the annotation @XmlAttribute to define a property or field to be handled as an XML attribute.

XmlRootElement Example

Illustrates how to use the annotation @XmlRootElement to define an XML element name for the XML schema type of the corresponding class.

XmlSchemaType Class Example

Illustrates how to use the annotation @XmlSchemaType to customize the mapping of a property or field to an XML built-in type.

XmlType Example

Illustrates how to use the annotation @XmlType to map a class or enum type to an XML schema type.

JAXB Compiler Options

The JAXB XJC schema binding compiler transforms, or binds, a source XML schema to a set of JAXB content classes in the Java programming language. The compiler, xjc, is provided in two flavors in the Application Server: xjc.sh (Solaris/Linux) and xjc.bat (Windows). Both xjc.sh and xjc.bat take the same command-line options. You can display quick usage instructions by invoking the scripts without any options, or with the -help switch. The syntax is as follows:

xjc [-options ...] schema

The xjc command line options are as follows:

-nv

Do not perform strict validation of the input schema or schemas. By default, xjc performs strict validation of the source schema before processing. Note that this does not mean the binding compiler will not perform any validation; it simply means that it will perform less-strict validation.

-extension

By default, the XJC binding compiler strictly enforces the rules outlined in the Compatibility chapter of the JAXB Specification. In the default (strict) mode, you are also limited to using only the binding customizations defined in the specification. By using the -extension switch, you will be allowed to use the JAXB Vendor Extensions.

-b file

Specify one or more external binding files to process. (Each binding file must have its own -b switch.) The syntax of the external binding files is extremely flexible. You may have a single binding file that contains customizations for multiple schemas or you can break the customizations into multiple bindings files. In addition, the ordering of the schema files and binding files on the command line does not matter.

-d dir

By default, xjc will generate Java content classes in the current directory. Use this option to specify an alternate output directory. The directory must already exist; xjc will not create it for you.

-p package

Specify an alternate output directory. By default, the XJC binding compiler will generate the Java content classes in the current directory. The output directory must already exist; the XJC binding compiler will not create it for you.

-proxy proxy

Specify the HTTP/HTTPS proxy. The format is [user[:password]@]proxyHost[:proxyPort]. The old -host and -port options are still supported by the Reference Implementation for backwards compatibility, but they have been deprecated.

-classpath arg

Specify where to find client application class files used by the <jxb:javaType> and <xjc:superClass> customizations.

-catalog file

Specify catalog files to resolve external entity references. Supports TR9401, XCatalog, and OASIS XML Catalog format. For more information, see the XML Entity and URI Resolvers document or examine the catalog-resolver sample application.

-readOnly

Force the XJC binding compiler to mark the generated Java sources read-only. By default, the XJC binding compiler does not write-protect the Java source files it generates.

-npa

Suppress the generation of package level annotations into **/package-info.java. Using this switch causes the generated code to internalize those annotations into the other generated classes.

-xmlschema

Treat input schemas as W3C XML Schema (default). If you do not specify this switch, your input schemas will be treated as W3C XML Schema.

-quiet

Suppress compiler output, such as progress information and warnings.

-help

Display a brief summary of the compiler switches.

-version

Display the compiler version information.

-Xlocator

Enable source location support for generated code.

-Xsync-methods

Generate accessor methods with the synchronized keyword.

-mark-generated

Mark the generated code with the -@javax.annotation.Generated annotation.

JAXB Schema Generator Option

The JAXB Schema Generator, schemagen, creates a schema file for each namespace referenced in your Java classes. The schema generator can be launched using the appropriate schemagen shell script in the bin directory for your platform. The schema generator processes Java source files only. If your Java sources reference other classes, those sources must be accessible from your system CLASSPATH environment variable, otherwise errors will occur when the schema is generated. There is no way to control the name of the generated schema files.

You can display quick usage instructions by invoking the scripts without any options, or with the -help option. The syntax is as follows:

schemagen [-d path] [java-source-files]

The -d path option specifies the location of the processor- and javac-generated class files.

About the Schema-to-Java Bindings

When you run the JAXB binding compiler against the po.xsd XML schema used in the basic examples (Unmarshal Read, Modify Marshal, Unmarshal Validate), the JAXB binding compiler generates a Java package named primer.po containing 11 classes, making a total of 12 classes in each of the basic examples, as described in Table 17–12.

Table 17–12 Schema-Derived JAXB Classes in the Basic Examples

Class 

Description 

primer/po/Comment.java

Public interface extending javax.xml.bind.Element; binds to the global schema element named comment. Note that JAXB generates element interfaces for all global element declarations.

primer/po/Items.java

Public interface that binds to the schema complexType named Items.

primer/po/ObjectFactory.java

Public class extending com.sun.xml.bind.DefaultJAXBContextImpl; used to create instances of specified interfaces. For example, the ObjectFactory createComment() method instantiates a Comment object.

primer/po/PurchaseOrder.java

Public interface extending javax.xml.bind.Element, and PurchaseOrderType; binds to the global schema element named PurchaseOrder.

primer/po/PurchaseOrderType.java

Public interface that binds to the schema complexType named PurchaseOrderType.

primer/po/USAddress.java

Public interface that binds to the schema complexType named USAddress.

primer/po/impl/CommentImpl.java

Implementation of Comment.java

primer/po/impl/ItemsImpl.java

Implementation of Items.java

primer/po/impl/PurchaseOrderImpl.java

Implementation of PurchaseOrder.java

primer/po/impl/PurchaseOrderTypeImpl.java

Implementation of PurchaseOrderType.java

primer/po/impl/USAddressImpl.java

Implementation of USAddress.java


Note –

You should never directly use the generated implementation classes (*Impl.java in the packagename/impl/ directory). These classes cannot be referenced directly because the class names in this directory are not standardized by the JAXB specification. The ObjectFactory method is the only portable means to create an instance of a schema-derived interface. There is also an ObjectFactory.newInstance(Class JAXBinterface) method that enables you to create instances of interfaces.


These classes and their specific bindings to the source XML schema for the basic examples are described in Table 17–13. .

Table 17–13 Schema-to-Java Bindings for the Basic Examples

XML Schema 

JAXB Binding 

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>

PurchaseOrder.java

<xsd:element name="comment" type="xsd:string"/>

Comment.java

<xsd:complexType name="PurchaseOrderType">
 <xsd:sequence>
 <xsd:element name="shipTo" type="USAddress"/>
 <xsd:element name="billTo" type="USAddress"/>
 <xsd:element ref="comment" minOccurs="0"/>
 <xsd:element name="items" type="Items"/>
 </xsd:sequence>
 <xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>

PurchaseOrderType.java

<xsd:complexType name="USAddress">
 <xsd:sequence>
 <xsd:element name="name" type="xsd:string"/>
 <xsd:element name="street" type="xsd:string"/>
 <xsd:element name="city" type="xsd:string"/>
 <xsd:element name="state" type="xsd:string"/>
 <xsd:element name="zip" type="xsd:decimal"/>
 </xsd:sequence>
<xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
</xsd:complexType>

USAddress.java

<xsd:complexType name="Items">
 <xsd:sequence>
 <xsd:element name="item" minOccurs="1" maxOccurs="unbounded">

Items.java

<xsd:complexType>
 <xsd:sequence>
 <xsd:element name="productName" type="xsd:string"/>
 <xsd:element name="quantity">
 <xsd:simpleType>
 <xsd:restriction base="xsd:positiveInteger">
 <xsd:maxExclusive value="100"/>
 </xsd:restriction>
 </xsd:simpleType>
 </xsd:element>
 <xsd:element name="USPrice" type="xsd:decimal"/>
 <xsd:element ref="comment" minOccurs="0"/>
 <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
 </xsd:sequence>
 <xsd:attribute name="partNum" type="SKU" use="required"/>
</xsd:complexType>

Items.ItemType

</xsd:element>
 </xsd:sequence>
</xsd:complexType>
 
<!-- Stock Keeping Unit, a code for identifying products -->
 
<xsd:simpleType name="SKU">
 <xsd:restriction base="xsd:string">
 <xsd:pattern value="\d{3}-[A-Z]{2}"/>
 </xsd:restriction>
</xsd:simpleType>
 
</xsd:schema>
 

Schema-Derived JAXB Classes

The sections that follow briefly explain the functions of the following individual classes generated by the JAXB binding compiler for the Basic examples:

Comment Class

In Comment.java:

Items Class

In Items.java:

ObjectFactory Class

In ObjectFactory.java:

PurchaseOrder Class

In PurchaseOrder.java:

PurchaseOrderType Class

In PurchaseOrderType.java:

USAddress Class

In USAddress.java:

Basic JAXB Examples

This section describes the Basic examples (Modify Marshal, Unmarshal Validate) that demonstrate how to:

Modify Marshal Example

The Modify Marshal example demonstrates how to modify a Java content tree.

  1. The tut-install/javaeetutorial5/examples/jaxb/modify-marshal/src/modifymarshal/Main.java class declares imports for three standard Java classes plus four JAXB binding framework classes and primer.po package:

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.math.BigDecimal;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    import primer.po.*;
  2. A JAXBContext instance is created for handling classes generated in primer.po.

    JAXBContext jc = JAXBContext.newInstance( "primer.po" );
  3. An Unmarshaller instance is created, and po.xml is unmarshalled.

    Unmarshaller u = jc.createUnmarshaller();
    PurchaseOrder po = (PurchaseOrder)u.unmarshal( new FileInputStream( "po.xml" ) );
  4. set methods are used to modify information in the address branch of the content tree.

    USAddress address = po.getBillTo();
    address.setName( "John Bob" );
    address.setStreet( "242 Main Street" );
    address.setCity( "Beverly Hills" );
    address.setState( "CA" );
    address.setZip( new BigDecimal( "90210" ) );
  5. A Marshaller instance is created, and the updated XML content is marshalled to system.out. The setProperty API is used to specify output encoding; in this case formatted (human readable) XML format.

    Marshaller m = jc.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    m.marshal( po, System.out );

Building and Running the Modify Marshal Example Using NetBeans IDE

Follow these instructions to build and run the Modify Marshal example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the modify-marshal folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the modify-marshal project and select Run.

Building and Running the Modify Marshal Example Using Ant

To compile and run the Modify Marshal example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/modify-marshal/ directory and type the following:


ant runapp

Unmarshal Validate Example

The Unmarshal Validate example demonstrates how to enable validation during unmarshalling. Note that JAXB provides functions for validation during unmarshalling but not during marshalling. Validation is explained in more detail in More about Validation.

  1. The tut-install/javaeetutorial5/examples/jaxb/unmarshal-validate/src/unmarshalvalidate/Main.java class declares imports for three standard Java classes plus seven JAXB binding framework classes and the primer.po package:

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.math.BigDecimal;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBException;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.UnmarshalException;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.bind.ValidationEvent;
    import javax.xml.bind.util.ValidationEventCollector;
    import primer.po.*;
  2. A JAXBContext instance is created for handling classes generated in primer.po.

    JAXBContext jc = JAXBContext.newInstance( "primer.po" );
  3. An Unmarshaller instance is created.

    Unmarshaller u = jc.createUnmarshaller();
  4. The default JAXB Unmarshaller ValidationEventHandler is enabled to send to validation warnings and errors to system.out. The default configuration causes the unmarshal operation to fail upon encountering the first validation error.

    u.setValidating( true );
  5. An attempt is made to unmarshal po.xml into a Java content tree. For the purposes of this example, the po.xml contains a deliberate error.

    PurchaseOrder po = (PurchaseOrder)u.unmarshal( new FileInputStream("po.xml"));
  6. The default validation event handler processes a validation error, generates output to system.out, and then an exception is thrown.

    } catch( UnmarshalException ue ) {
        System.out.println( "Caught UnmarshalException" );
    } catch( JAXBException je ) { 
        je.printStackTrace();
    } catch( IOException ioe ) {
        ioe.printStackTrace();
    }

Building and Running the Unmarshal Validate Example Using NetBeans IDE

Follow these instructions to build and run the Unmarshal Validate example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the unmarshal-validate folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the unmarshal-validate project and select Run.

Building and Running the Unmarshal Validate Example Using Ant

To compile and run the Unmarshal Validate example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/unmarshal-validate/ directory and type the following:


ant runapp

Customizing JAXB Bindings

The next part of this chapter describes several examples that build on the concepts demonstrated in the Basic examples.

The goal of this section is to illustrate how to customize JAXB bindings by means of custom binding declarations made in either of two ways:

Unlike the examples in Basic JAXB Examples, which focus on the Java code in the respective Main.java class files, the examples here focus on customizations made to the XML schema before generating the schema-derived Java binding classes.


Note –

Although JAXB binding customizations must currently be made by hand, it is envisioned that a tool/wizard might eventually be written by Sun or a third party to make this process more automatic. One of the goals of the JAXB technology is to standardize the format of binding declarations, thereby making it possible to create customization tools and to provide a standard interchange format between JAXB implementations.


This section just begins to scratch the surface of customizations you can make to JAXB bindings and validation methods. For more information, refer to the JAXB Specification .

Why Customize?

In most cases, the default bindings generated by the JAXB binding compiler will be sufficient to meet your needs. There are cases, however, in which you might want to modify the default bindings. Some of these include:

Customization Overview

This section explains some core JAXB customization concepts:

Inline and External Customizations

Customizations to the default JAXB bindings are made in the form of binding declarations passed to the JAXB binding compiler. These binding declarations can be made in either of two ways:

For some people, using inline customizations is easier because you can see your customizations in the context of the schema to which they apply. Conversely, using an external binding customization file enables you to customize JAXB bindings without having to modify the source schema, and enables you to easily apply customizations to several schema files at once.


Note –

You can combine the two types of customizations. For example, you could include a reference to an external binding customizations file in an inline annotation. However, you cannot declare both an inline and external customization on the same schema element.


Each of these types of customization is described in more detail below.

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.

<xs:annotation>
   <xs:appinfo>
      .
      .
      binding declarations      .
      .
   </xs:appinfo>
</xs: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 XMLSchema namespace prefix must be used with the <annotation> and <appinfo> declaration tags. In the example above, xs: is used as the namespace prefix, so the declarations are tagged <xs:annotation> and <xs: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 = "xs:anyURI">
   <jxb:bindings node = "xs:string">*
      <binding declaration>
   <jxb:bindings>
</jxb:bindings>

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="/xs:schema">

A subsequent schemaLocation/node declaration, say for a simpleType element named ZipCodeType in the above schema, would take the form:

<jxb:bindings node="//xs:simpleType[@name=’ZipCodeType’]">

Binding Customization File Format

Binding customization files should be straight ASCII text. The name or extension does not matter, although a typical extension, used in this chapter, is .xjb.

Passing Customization Files to the JAXB Binding Compiler

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 or schemas 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; for example:

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.

For more information about xjc compiler options in general, see JAXB Compiler Options.

Restrictions for External Binding Customizations

There are several rules that apply to binding declarations made in an external binding customization file that do not apply to similar declarations made inline in a source schema:

To summarize these rules, the external binding element <jxb:bindings> is only recognized for processing by a JAXB binding compiler in three cases:

Scope, Inheritance, and Precedence

Default JAXB bindings can be customized or overridden at four different levels, or scopes.

Figure 17–3 illustrates the inheritance and precedence of customization declarations. Specifically, declarations towards the top of the pyramid inherit and supersede declarations below them. For example, Component declarations inherit from and supersede Definition declarations; Definition declarations inherit and supersede Schema declarations; and Schema declarations inherit and supersede Global declarations.

Figure 17–3 Customization Scope Inheritance and Precedence

Diagram of scope inheritance. Top to bottom: Component
Scope, Definition Scope, Schema Scope, and Global Scope.

Customization Syntax

The syntax for the four types of JAXB binding declarations, as well as the syntax for the XML-to-Java data type binding declarations and the customization namespace prefix, are described below.

Global Binding Declarations

Global scope customizations are declared with <globalBindings>. The syntax for global scope customizations is as follows:

<globalBindings>
    [ collectionType = "collectionType" ]
    [ fixedAttributeAsConstantProperty    = "true" | "false" | "1" | "0" ]
    [ generateIsSetMethod    = "true" | "false" | "1" | "0" ]
    [ enableFailFastCheck = "true" | "false" | "1" | "0" ]
    [ choiceContentProperty = "true" | "false" | "1" | "0" ]
    [ underscoreBinding = "asWordSeparator" | "asCharInWord" ]
    [ typesafeEnumBase = "typesafeEnumBase" ]
    [ typesafeEnumMemberName = "generateName" | "generateError" ]
    [ enableJavaNamingConventions = "true" | "false" | "1" | "0" ]
    [ bindingStyle = "elementBinding" | "modelGroupBinding" ]
    [ <javaType> ... </javaType> ]*
</globalBindings>

<globalBindings> declarations are only valid in the annotation element of the top-level schema element. There can only be a single instance of a <globalBindings> declaration in any given schema or binding declarations file. If one source schema includes or imports a second source schema, the <globalBindings> declaration must be declared in the first source schema.

Schema Binding Declarations

Schema scope customizations are declared with <schemaBindings>. The syntax for schema scope customizations is:

<schemaBindings>
    [ <package> package </package> ]
    [ <nameXmlTransform> ... </nameXmlTransform> ]*
</schemaBindings>
    
<package [ name = "packageName" ]
    [ <javadoc> ... </javadoc> ]
</package>

<nameXmlTransform>
    [ <typeName [ suffix="suffix" ]
                [ prefix="prefix" ] /> ]
    [ <elementName [ suffix="suffix" ]
                   [ prefix="prefix" ] /> ]
    [ <modelGroupName [ suffix="suffix" ]
                      [ prefix="prefix" ] /> ]
    [ <anonymousTypeName [ suffix="suffix" ]
                         [ prefix="prefix" ] /> ]
</nameXmlTransform>

As shown above, <schemaBinding> declarations include two subcomponents:

Class Binding Declarations

The <class> binding declaration enables you to customize the binding of a schema element to a Java content interface or a Java Element interface. <class> declarations can be used to customize:

The syntax for <class> customizations is:

<class [ name = "className"]
   [ implClass= "implClass" ] >
   [ <javadoc> ... </javadoc> ]
</class>

Property Binding Declarations

The <property> binding declaration enables you to customize the binding of an XML schema element to its Java representation as a property. The scope of customization can either be at the definition level or component level depending upon where the <property> binding declaration is specified.

The syntax for <property> customizations is:

<property
    [ name = "propertyName"]
    [ collectionType = "propertyCollectionType" ]
    [ fixedAttributeAsConstantProperty = "true" | "false" | "1" | "0" ]
    [ generateIsSetMethod = "true" | "false" | "1" | "0" ]
    [ enableFailFastCheck ="true" | "false" | "1" | "0" ]
    [ <baseType> ... </baseType> ]
    [ <javadoc> ... </javadoc> ]
</property>

<baseType>
    <javaType> ... </javaType>
</baseType>

javaType Binding Declarations

The <javaType> declaration provides a way to customize the translation of XML data types to and from Java data types. XML provides more data types than Java, and so the <javaType> declaration lets you specify custom data type bindings when the default JAXB binding cannot sufficiently represent your schema.

The target Java data type can be a Java built-in data type or an application-specific Java data type. If an application-specific data type is used as the target, your implementation must also provide parse and print methods for unmarshalling and marshalling data. To this end, the JAXB specification supports a parseMethod and printMethod:

If you prefer to define your own data type conversions, JAXB defines a static class, DatatypeConverter, to assist in the parsing and printing of valid lexical representations of the XML Schema built-in data types.

The syntax for the <javaType> customization is:

<javaType name= "javaType"
    [ xmlType= "xmlType" ]
    [ hasNsContext = "true" | "false" ]
    [ parseMethod= "parseMethod" ]
    [ printMethod= "printMethod" ]>

The <javaType> declaration can be used in:

See MyDatatypeConverter Class for an example of how <javaType> declarations and the DatatypeConverterInterface interface are implemented in a custom data type converter class.

Typesafe Enumeration Binding Declarations

The typesafe enumeration declarations provide a localized way to map XML simpleType elements to Java typesafe enum classes. There are two types of typesafe enumeration declarations you can make:

In both cases, there are two primary limitations on this type of customization:

The syntax for the <typesafeEnumClass> customization is:

<typesafeEnumClass
    [ name = "enumClassName" ]
    [ <typesafeEnumMember> ... </typesafeEnumMember> ]*
    [ <javadoc> enumClassJavadoc </javadoc> ]
</typesafeEnumClass>

The syntax for the <typesafeEnumMember> customization is:

<typesafeEnumMember name = "enumMemberName">
                    [ value = "enumMemberValue" ]
    [ <javadoc> enumMemberJavadoc </javadoc> ]
</typesafeEnumMember>

For inline annotations, the <typesafeEnumClass> declaration must be specified in the annotation element of the <simpleType> element. The <typesafeEnumMember> must be specified in the annotation element of the enumeration member. This allows the enumeration member to be customized independently from the enumeration class.

For information about typesafe enum design patterns, see the sample chapter of Joshua Bloch’s Effective Java Programming on the Java Developer Connection.

javadoc Binding Declarations

The <javadoc> declaration lets you add custom Javadoc tool annotations to schema-derived JAXB packages, classes, interfaces, methods, and fields. Note that <javadoc> declarations cannot be applied globally; they are only valid as sub-elements of other binding customizations.

The syntax for the <javadoc> customization is:

<javadoc>
    Contents in &lt;b>Javadoc&lt;\b> format.
</javadoc>

or

<javadoc>
    <<![CDATA[
    Contents in <b>Javadoc<\b> format
    ]]>
</javadoc>

Note that documentation strings in <javadoc> declarations applied at the package level must contain <body> open and close tags; for example:

<jxb:package name="primer.myPo">
  <jxb:javadoc>
    <![CDATA[<body>Package level documentation for generated package primer.myPo.</body>]]>
  </jxb:javadoc>
</jxb:package>

Customization Namespace Prefix

All standard JAXB binding declarations must be preceded by a namespace prefix that maps to the JAXB namespace URI (http://java.sun.com/xml/ns/jaxb). For example, in this sample, jxb: is used. To this end, any schema you want to customize with standard JAXB binding declarations must include the JAXB namespace declaration and JAXB version number at the top of the schema file. For example, in po.xsd for the Customize Inline example, the namespace declaration is as follows:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
            jxb:version="1.0">

A binding declaration with the jxb namespace prefix would then take the form:

<xsd:annotation>
   <xsd:appinfo>
      <jxb:globalBindings binding declarations />
      <jxb:schemaBindings>
         .
         .
         binding declarations         .
         .
      </jxb:schemaBindings>
   </xsd:appinfo>
</xsd:annotation>

Note that in this example, the globalBindings and schemaBindings declarations are used to specify, respectively, global scope and schema scope customizations. These customization scopes are described in more detail in Scope, Inheritance, and Precedence.

Customize Inline Example

The Customize Inline example illustrates some basic customizations made by means of inline annotations to an XML schema named po.xsd. In addition, this example implements a custom data type converter class, MyDatatypeConverter.java, which illustrates print and parse methods in the <javaType> customization for handling custom data type conversions.

    To summarize this example:

  1. po.xsd is an XML schema containing inline binding customizations.

  2. MyDatatypeConverter.java is a Java class file that implements print and parse methods specified by <javaType> customizations in po.xsd.

  3. Main.java is the primary class file in the Customize Inline example, which uses the schema-derived classes generated by the JAXB compiler.

Building and Running the Customize Inline Example Using NetBeans IDE

Follow these instructions to build and run the Customize Inline example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the inline-customize folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the inline-customize project and select Run.

Building and Running the Customize Inline Example Using Ant

To compile and run the Customize Inline example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/inline-customize/ directory and type the following:


ant runapp

Key customizations in this sample, and the custom MyDatatypeConverter.java class, are described in more detail below.

Customized Schema

The customized schema used in the Customize Inline example is in the file tut-install/javaeetutorial5/examples/jaxb/inline-customize/po.xsd. The customizations are in the <xsd:annotation> tags.

Global Binding Declarations

The code below shows the globalBindings declarations in po.xsd:

<jxb:globalBindings
        fixedAttributeAsConstantProperty="true"
        collectionType="java.util.Vector"
        typesafeEnumBase="xsd:NCName"
        choiceContentProperty="false"
        typesafeEnumMemberName="generateError"
        bindingStyle="elementBinding"
        enableFailFastCheck="false"
        generateIsSetMethod="false"
        underscoreBinding="asCharInWord"/>

In this example, all values are set to the defaults except for collectionType.

Schema Binding Declarations

The following code shows the schema binding declarations in po.xsd:

<jxb:schemaBindings>
  <jxb:package name="primer.myPo">
    <jxb:javadoc>
      <![CDATA[<body> Package level documentation for generated package primer.myPo.</body>]]>
    </jxb:javadoc>
  </jxb:package>
  <jxb:nameXmlTransform>
    <jxb:elementName suffix="Element"/>
  </jxb:nameXmlTransform>
</jxb:schemaBindings>

Class Binding Declarations

The following code shows the class binding declarations in po.xsd:

<xsd:complexType name="PurchaseOrderType">
      <xsd:annotation>
      <xsd:appinfo>
         <jxb:class name="POType">
            <jxb:javadoc>
            A &lt;b>Purchase Order&lt;/b> consists of addresses and items.
            </jxb:javadoc>
         </jxb:class>
      </xsd:appinfo>
      </xsd:annotation>
      .
      .
      .
</xsd:complexType>

The Javadoc tool annotations for the schema-derived POType class will contain the description "A &lt;b>Purchase Order&lt;/b> consists of addresses and items." The &lt; is used to escape the opening bracket on the <b> HTML tags.


Note –

When a <class> customization is specified in the appinfo element of a complexType definition, as it is here, the complexType definition is bound to a Java content interface.


Later in po.xsd, another <javadoc> customization is declared at this class level, but this time the HTML string is escaped with CDATA:

<xsd:annotation>
  <xsd:appinfo>
    <jxb:class>
      <jxb:javadoc>
        <![CDATA[ First line of documentation for a <b>USAddress</b>.]]>
      </jxb:javadoc>
    </jxb:class>
  </xsd:appinfo>
</xsd:annotation>

Note –

If you want to include HTML markup tags in a <jaxb:javadoc> customization, you must enclose the data within a CDATA section or escape all left angle brackets using &lt;. See XML 1.0 2nd Edition for more information.


Property Binding Declarations

Of particular interest here is the generateIsSetMethod customization, which causes two additional property methods, isSetQuantity and unsetQuantity, to be generated. These methods enable a client application to distinguish between schema default values and values occurring explicitly within an instance document.

For example, in po.xsd:

<xsd:complexType name="Items">
   <xsd:sequence>
      <xsd:element name="item" minOccurs="1" maxOccurs="unbounded">
         <xsd:complexType>
            <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity" default="10">
            <xsd:annotation>
               <xsd:appinfo>
                  <jxb:property generateIsSetMethod="true"/>
               </xsd:appinfo>
            </xsd:annotation>
         ...
         </xsd:complexType>
      </xsd:element>
   </xsd:sequence>
</xsd:complexType>

The @generateIsSetMethod applies to the quantity element, which is bound to a property within the Items.ItemType interface. unsetQuantity and isSetQuantity methods are generated in the Items.ItemType interface.

MyDatatypeConverter Class

The class tut-install/javaeetutorial5/examples/jaxb/inline-customize/src/inlinecustomize/primer/MyDatatypeConverter, shown below, provides a way to customize the translation of XML data types to and from Java data types by means of a <javaType> customization.

package primer;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;

public class MyDatatypeConverter {

    public static short parseIntegerToShort(String value) {
        BigInteger result = DatatypeConverter.parseInteger(value);
        return (short)(result.intValue());
    }

    public static String printShortToInteger(short value) {
        BigInteger result = BigInteger.valueOf(value);
        return DatatypeConverter.printInteger(result);
    }

    public static int parseIntegerToInt(String value) {
        BigInteger result = DatatypeConverter.parseInteger(value);
        return result.intValue();
    }

    public static String printIntToInteger(int value) {
        BigInteger result = BigInteger.valueOf(value);
        return DatatypeConverter.printInteger(result);
    }
};

The following code shows how the MyDatatypeConverter class is referenced in a <javaType> declaration in po.xsd:

<xsd:simpleType name="ZipCodeType">
  <xsd:annotation>
     <xsd:appinfo>
        <jxb:javaType name="int" 
            parseMethod="primer.MyDatatypeConverter.parseIntegerToInt" 
            printMethod="primer.MyDatatypeConverter.printIntTo Integer" />
     </xsd:appinfo>
  </xsd:annotation>
    <xsd:restriction base="xsd:integer">
    <xsd:minInclusive value="10000"/>
    <xsd:maxInclusive value="99999"/>
  </xsd:restriction>
</xsd:simpleType>

In this example, the jxb:javaType binding declaration overrides the default JAXB binding of this type to java.math.BigInteger. For the purposes of the Customize Inline example, the restrictions on ZipCodeType (specifically, that legal United States ZIP codes are limited to five digits) make it so all valid values can easily fit within the Java primitive data type int. Note also that, because <jxb:javaType name="int"/> is declared within ZipCodeType, the customization applies to all JAXB properties that reference this simpleType definition, including the getZip and setZip methods.

Datatype Converter Example

The Datatype Converter example is very similar to the Customize Inline example. As with the Customize Inline example, the customizations in the Datatype Converter example are made by using inline binding declarations in the XML schema for the application, po.xsd.

The global, schema, and package, and most of the class customizations for the Customize Inline and Datatype Converter examples are identical. Where the Datatype Converter example differs from the Customize Inline example is in the parseMethod and printMethod used for converting XML data to the Java int data type.

Specifically, rather than using methods in the custom MyDataTypeConverter class to perform these data type conversions, the Datatype Converter example uses the built-in methods provided by javax.xml.bind.DatatypeConverter:

<xsd:simpleType name="ZipCodeType">
  <xsd:annotation>
      <xsd:appinfo>
        <jxb:javaType name="int"
            parseMethod="javax.xml.bind.DatatypeConverter.parseInt"
            printMethod="javax.xml.bind.DatatypeConverter.printInt"/>
     </xsd:appinfo>
  </xsd:annotation>
  <xsd:restriction base="xsd:integer">
    <xsd:minInclusive value="10000"/>
    <xsd:maxInclusive value="99999"/>
  </xsd:restriction>
</xsd:simpleType>

Building and Running the Datatype Converter Example Using NetBeans IDE

Follow these instructions to build and run the Datatype Converter example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the datatypeconverter folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the datatypeconverter project and select Run.

Building and Running the Datatype Converter Example Using Ant

To compile and run the Datatype Converter example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/datatypeconverter/ directory and type the following:


ant runapp

Binding Declaration Files

The following sections provide information about binding declaration files:

JAXB Version, Namespace, and Schema Attributes

All JAXB binding declarations files must begin with:

The version, namespace, and schema declarations in bindings.xjb are as follows:

<jxb:bindings version="1.0"
              xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <jxb:bindings schemaLocation="po.xsd" node="/xs:schema">
        ...
        binding-declarations        ...
  </jxb:bindings>
<!-- schemaLocation="po.xsd" node="/xs:schema" -->
</jxb:bindings>

JAXB Version Number

An XML file with a root element of <jaxb:bindings> is considered an external binding file. The root element must specify the JAXB version attribute with which its binding declarations must comply; specifically the root <jxb:bindings> element must contain either a <jxb:version> declaration or a version attribute. By contrast, when making binding declarations inline, the JAXB version number is made as attribute of the <xsd:schema> declaration:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
            jxb:version="1.0">

Namespace Declarations

As shown in JAXB Version, Namespace, and Schema Attributes, the namespace declarations in the external binding declarations file include both the JAXB namespace and the XMLSchema namespace. Note that the prefixes used in this example could in fact be anything you want; the important thing is to consistently use whatever prefixes you define here in subsequent declarations in the file.

Schema Name and Schema Node

The fourth line of the code in JAXB Version, Namespace, and Schema Attributes specifies the name of the schema to which this binding declarations file will apply, and the schema node at which the customizations will first take effect. Subsequent binding declarations in this file will reference specific nodes within the schema, but this first declaration should encompass the schema as a whole; for example, in bindings.xjb:

<jxb:bindings schemaLocation="po.xsd" node="/xs:schema">

Global and Schema Binding Declarations

The global schema binding declarations in bindings.xjb are the same as those in po.xsd for the Datatype Converter example. The only difference is that because the declarations in po.xsd are made inline, you need to embed them in <xs:appinfo> elements, which are in turn embedded in <xs:annotation> elements. Embedding declarations in this way is unnecessary in the external bindings file.

<jxb:globalBindings
  fixedAttributeAsConstantProperty="true"
  collectionType="java.util.Vector"
  typesafeEnumBase="xs:NCName"
  choiceContentProperty="false"
  typesafeEnumMemberName="generateError"
  bindingStyle="elementBinding"
  enableFailFastCheck="false"
  generateIsSetMethod="false"
  underscoreBinding="asCharInWord"/>
<jxb:schemaBindings>
  <jxb:package name="primer.myPo">
    <jxb:javadoc>
      <![CDATA[<body>Package level documentation for generated package primer.myPo.</body>]]>
    </jxb:javadoc>
  </jxb:package>
  <jxb:nameXmlTransform>
    <jxb:elementName suffix="Element"/>
  </jxb:nameXmlTransform>
</jxb:schemaBindings>

By comparison, the syntax used in po.xsd for the Datatype Converter example is:

<xsd:annotation>
  <xsd:appinfo>
    <jxb:globalBindings
        ...
        binding-declarations
        ...
    <jxb:schemaBindings>
        ...
        binding-declarations
        ...
    </jxb:schemaBindings>
  </xsd:appinfo>
</xsd:annotation>

Class Declarations

The class-level binding declarations in bindings.xjb differ from the analogous declarations in po.xsd for the Datatype Converter example in two ways:

For example, the following code shows binding declarations for the complexType named USAddress.

<jxb:bindings node="//xs:complexType[@name=’USAddress’]">
  <jxb:class>
    <jxb:javadoc>
      <![CDATA[First line of documentation for a <b>USAddress</b>.]]>
    </jxb:javadoc>
  </jxb:class>

  <jxb:bindings node=".//xs:element[@name=’name’]">
    <jxb:property name="toName"/>
  </jxb:bindings>

  <jxb:bindings node=".//xs:element[@name=’zip’]">
    <jxb:property name="zipCode"/>
  </jxb:bindings>
</jxb:bindings>
<!-- node="//xs:complexType[@name=’USAddress’]" -->

Note in this example that USAddress is the parent of the child elements name and zip, and therefore a </jxb:bindings> tag encloses the bindings declarations for the child elements as well as the class-level javadoc declaration.

External Customize Example

The External Customize example is identical to the Datatype Converter example, except that the binding declarations in the External Customize example are made by means of an external binding declarations file rather than inline in the source XML schema.

The binding customization file used in the External Customize example is tut-install/javaeetutorial5/examples/jaxb/external-customize/binding.xjb.

This section compares the customization declarations in bindings.xjb with the analogous declarations used in the XML schema, po.xsd, in the Datatype Converter example. The two sets of declarations achieve precisely the same results.

Building and Running the External Customize Example Using NetBeans IDE

Follow these instructions to build and run the External Customize example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the external-customize folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the external-customize project and select Run.

Building and Running the External Customize Example Using Ant

To compile and run the External Customize example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/external-customize/ directory and type the following:


ant runapp

Java-to-Schema Examples

The Java-to-Schema examples show how to use annotations to map Java classes to XML schema.

    If you are using JDK 6, perform the following steps before you run any of the Java-to-Schema examples:

  1. Change to one of the Java-to-Schema example directories (for example, tut-install/javaeetutorial5/examples/jaxb/j2s-create-marshal.

  2. Run the following Ant command:


    ant update-endorsed
    

    This command creates an endorsed directory in the JDK and copies the webservices-api.jar file from the Application Server's lib/endorsed/ directory into it.

Create Marshal Example

The Create Marshal example illustrates Java-to-schema databinding. It demonstrates marshalling and unmarshalling of JAXB annotated classes and also shows how to enable JAXP 1.3 validation at unmarshal time using a schema file that was generated from the JAXB mapped classes.

The schema file, bc.xsd, was generated with the following commands:


schemagen src/cardfile/*.java
cp schema1.xsd bc.xsd

Note that schema1.xsd, was copied to bc.xsd; schemagen does not allow you to specify a schema name of your choice.

Building and Running the Create Marshal Example Using NetBeans IDE

Follow these instructions to build and run the Create Marshal example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-create-marshal folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-create-marshal project and select Run.

Building and Running the Create Marshal Example Using Ant

To compile and run the Create Marshal example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-create-marshal/ directory and type the following:


ant runapp

XmlAccessorOrder Example

The j2s-xmlAccessorOrder example shows how to use the @XmlAccessorOrder and @XmlType.propOrder annotations to dictate the order in which XML content is marshalled/unmarshalled by a Java type.

With Java-to-schema mapping, a JavaBean’s properties and fields are mapped to an XML Schema type. The class elements are mapped to either an XML Schema complex type or an XML Schema simple type. The default element order for a generated schema type is currently unspecified because Java reflection does not impose a return order. The lack of reliable element ordering negatively impacts application portability. You can use two annotations, @XmlAccessorOrder and @XmlType.propOrder, to define schema element ordering for applications that need to be portable across JAXB Providers.

Using the @XmlAccessorOrder Annotation to Define Schema Element Ordering

The @XmlAccessorOrder annotation imposes one of two element ordering algorithms, AccessorOrder.UNDEFINED or AccessorOrder.ALPHABETICAL. AccessorOrder.UNDEFINED is the default setting. The order is dependent on the system’s reflection implementation. AccessorOrder.ALPHABETICAL orders the elements in lexicographic order as determined by java.lang.String.CompareTo(String anotherString).

You can define the @XmlAccessorOrder annotation for annotation type ElementType.PACKAGE on a class object. When the @XmlAccessorOrder annotation is defined on a package, the scope of the formatting rule is active for every class in the package. When defined on a class, the rule is active on the contents of that class.

There can be multiple @XmlAccessorOrder annotations within a package. The order of precedence is the innermost (class) annotation takes precedence over the outer annotation. For example, if @XmlAccessorOrder(AccessorOrder.ALPHABETICAL) is defined on a package and @XmlAccessorOrder(AccessorOrder.UNDEFINED) is defined on a class in that package, the contents of the generated schema type for the class would be in an unspecified order and the contents of the generated schema type for every other class in the package would be alphabetical order.

Using the @XmlType Annotation to Define Schema Element Ordering

The @XmlType annotation can be defined for a class. The annotation element propOrder() in the @XmlType annotation allows you to specify the content order in the generated schema type. When you use the @XmlType.propOrder annotation on a class to specify content order, all public properties and public fields in the class must be specified in the parameter list. Any public property or field that you want to keep out of the parameter list must be annotated with @XmlAttribute or @XmlTransient annotation.

The default content order for @XmlType.propOrder is {} or {""}, not active. In such cases, the active @XmlAccessorOrder annotation takes precedence. When class content order is specified by the @XmlType.propOrder annotation, it takes precedence over any active @XmlAccessorOrder annotation on the class or package. If the @XmlAccessorOrder and @XmlType.propOrder(A, B, ...) annotations are specified on a class, the propOrder always takes precedence regardless of the order of the annotation statements. For example, in the code below, the @XmlAccessorOrder annotation precedes the @XmlType.propOrder annotation.

@XmlAccessorOrder(AccessorOrder.ALPHABETICAL)
@XmlType(propOrder={"name", "city"})
public class USAddress {
            .
            .
    public String getCity() {return city;}
    public void setCity(String city) {this.city = city;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
            .
            .
}

In the code below, the @XmlType.propOrder annotation precedes the @XmlAccessorOrder annotation.

@XmlType(propOrder={"name", "city"})
@XmlAccessorOrder(AccessorOrder.ALPHABETICAL)
public class USAddress {
            .
            .
    public String getCity() {return city;}
    public void setCity(String city) {this.city = city;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
            .
            .
}

In both scenarios, propOrder takes precedence and the identical schema content shown below will be generated.

<xs:complexType name="usAddress">
   <xs:sequence>
        <xs:element name="name" type="xs:string" minOccurs="0"/>
        <xs:element name="city" type="xs:string" minOccurs="0"/>
   </xs:sequence>
</xs:complexType>

Schema Content Ordering in the Example

The purchase order code example demonstrates the effects of schema content ordering using the @XmlAccessorOrder annotation at the package and class level, and the @XmlType.propOrder annotation on a class.

Class package-info.java defines @XmlAccessorOrder to be ALPHABETICAL for the package. The public fields shipTo and billTo in class PurchaseOrderType will be affected in the generated schema content order by this rule. Class USAddress defines the @XmlType.propOrder annotation on the class. User of this annotation demonstrates user-defined property order superseding ALPHABETICAL order in the generated schema.

The generated schema file can be found in the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlAccessorOrder/build/schemas/ directory.

Building and Running the XmlAccessorOrder Example Using NetBeans IDE

Follow these instructions to build and run the XmlAccessorOrder example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlAccessorOrder folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlAccessorOrder project and select Run.

Building and Running the XmlAccessorOrder Example Using Ant

To compile and run the XmlAccessorOrder example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlAccessorOrder/ directory and type the following:


ant runapp

XmlAdapter Field Example

The XmlAdapter Field example demonstrates how to use the XmlAdapter interface and the @XmlJavaTypeAdapter annotation to provide a custom mapping of XML content into and out of a HashMap (field) that uses an int as the key and a String as the value.

Interface XmlAdapter and annotation @XmlJavaTypeAdapter are used for special processing of data types during unmarshalling/marshalling. There are a variety of XML data types for which the representation does not map easily into Java (for example, xs:DateTime and xs:Duration), and Java types which do not map conveniently into XML representations, for example implementations of java.util.Collection (such as List) and java.util.Map (such as HashMap) or for non-JavaBean classes.

The XmlAdapter interface and the @XmlJavaTypeAdapter annotation are provided for cases such as these. This combination provides a portable mechanism for reading/writing XML content into and out of Java applications.

The XmlAdapter interface defines the methods for data reading/writing.

/*
 *  ValueType - Java class that provides an XML representation
 *              of the data. It is the object that is used for
 *              marshalling and unmarshalling.
 *
 *  BoundType - Java class that is used to process XML content.
 */
public abstract class XmlAdapter<ValueType,BoundType> {
    // Do-nothing constructor for the derived classes.
    protected XmlAdapter() {}
    // Convert a value type to a bound type.
    public abstract BoundType unmarshal(ValueType v);
    // Convert a bound type to a value type.
    public abstract ValueType marshal(BoundType v);
 }

You can use the @XmlJavaTypeAdapter annotation to associate a particular XmlAdapter implementation with a Target type, PACKAGE, FIELD, METHOD, TYPE, or PARAMETER.

The XmlAdapter Field example shows how to use an XmlAdapter for mapping XML content into and out of a (custom) HashMap. The HashMap object, basket, in class KitchenWorldBasket, uses a key of type int and a value of type String. These data types should be reflected in the XML content that is read and written, so the XML content should look like this.

<basket>
     <entry key="9027">glasstop stove in black</entry>
     <entry key="288">wooden spoon</entry>
</basket>

The default schema generated for Java type HashMap does not reflect the desired format.

<xs:element name="basket">
   <xs:complexType>
     <xs:sequence>
       <xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
         <xs:complexType>
           <xs:sequence>
             <xs:element name="key" minOccurs="0" type="xs:anyType"/>
             <xs:element name="value" minOccurs="0" type="xs:anyType"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

In the default HashMap schema, key and value are both elements and are of data type anyType. The XML content will look like this:

<basket>
     <entry>
        <key>9027</>
        <value>glasstop stove in black</>
     </entry>
     <entry>
        <key>288</>
        <value>wooden spoon</>
    </entry>
</basket>

To resolve this issue, the example uses two Java classes, PurchaseList and PartEntry, that reflect the needed schema format for unmarshalling/marshalling the content. The XML schema generated for these classes is as follows:

<xs:complexType name="PurchaseListType">
    <xs:sequence>
        <xs:element name="entry" type="partEntry"
            nillable="true" maxOccurs="unbounded"
            minOccurs="0"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="partEntry">
    <xs:simpleContent>
        <xs:extension base="xs:string">
            <xs:attribute name="key" type="xs:int"
                use="required"/>
        </xs:extension>
    </xs:simpleContent>
</xs:complexType>

Class AdapterPurchaseListToHashMap implements the XmlAdapter interface. In class KitchenWorldBasket, the @XmlJavaTypeAdapter annotation is used to pair AdapterPurchaseListToHashMap with field HashMap basket. This pairing will cause the marshal/unmarshal method of AdapterPurchaseListToHashMap to be called for any corresponding marshal/unmarshal action on KitchenWorldBasket.

Building and Running the XmlAdapter Field Example Using NetBeans IDE

Follow these instructions to build and run the XmlAdapter Field example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlAdapter-field folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlAdapter-field project and select Run.

Building and Running the XmlAdapter Field Example Using Ant

To compile and run the XmlAdapter Field example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlAdapter-field/ directory and type the following:


ant runapp

XmlAttribute Field Example

The XmlAttribute Field example shows how to use the @XmlAttribute annotation to define a property or field to be treated as an XML attribute.

The @XmlAttribute annotation maps a field or JavaBean property to an XML attribute. The following rules are imposed:

When following the JavaBean programming paradigm, a property is defined by a get and set prefix on a field name.

int zip;
public int getZip(){return zip;}
public void setZip(int z){zip=z;}

Within a bean class, you have the choice of setting the @XmlAttribute annotation on one of three components: the field, the setter method, or the getter method. If you set the @XmlAttribute annotation on the field, the setter method will need to be renamed or there will be a naming conflict at compile time. If you set the @XmlAttribute annotation on one of the methods, it must be set on either the setter or getter method, but not on both.

The XmlAttribute Field example shows how to use the @XmlAttribute annotation on a static final field, on a field rather than on one of the corresponding bean methods, on a bean property (method), and on a field that is other than a collection type. In class USAddress, fields, country, and zip are tagged as attributes. The setZip method was disabled to avoid the compile error. Property state was tagged as an attribute on the setter method. You could have used the getter method instead. In class PurchaseOrderType, field cCardVendor is a non-collection type. It meets the requirement of being a simple type; it is an enum type.

Building and Running the XmlAttribute Field Example Using NetBeans IDE

Follow these instructions to build and run the XmlAttribute Field example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlAttribute-field folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlAttribute-field project and select Run.

Building and Running the XmlAttribute Field Example Using Ant

To compile and run the XmlAttribute Field example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlAttribute-field/ directory and type the following:


ant runapp

XmlRootElement Example

The XmlRootElement example demonstrates the use of the @XmlRootElement annotation to define an XML element name for the XML schema type of the corresponding class.

The @XmlRootElement annotation maps a class or an enum type to an XML element. At least one element definition is needed for each top-level Java type used for unmarshalling/marshalling. If there is no element definition, there is no starting location for XML content processing.

The @XmlRootElement annotation uses the class name as the default element name. You can change the default name by using the annotation attribute name. If you do, the specified name will then be used as the element name and the type name. It is common schema practice for the element and type names to be different. You can use the @XmlType annotation to set the element type name.

The namespace attribute of the @XmlRootElement annotation is used to define a namespace for the element.

Building and Running the XmlRootElement Example Using NetBeans IDE

Follow these instructions to build and run the XmlRootElement example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlRootElement folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlRootElement project and select Run.

Building and Running the XmlRootElement Example Using Ant

To compile and run the XmlRootElement example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlRootElement/ directory and type the following:


ant runapp

XmlSchemaType Class Example

The XmlSchemaType Class example demonstrates the use of the annotation @XmlSchemaType to customize the mapping of a property or field to an XML built-in type.

The @XmlSchemaType annotation can be used to map a Java type to one of the XML built-in types. This annotation is most useful in mapping a Java type to one of the nine date/time primitive data types.

When the @XmlSchemaType annotation is defined at the package level, the identification requires both the XML built-in type name and the corresponding Java type class. An @XmlSchemaType definition on a field or property takes precedence over a package definition.

The XmlSchemaType Class example shows how to use the @XmlSchemaType annotation at the package level, on a field, and on a property. File TrackingOrder has two fields, orderDate and deliveryDate, which are defined to be of type XMLGregorianCalendar. The generated schema will define these elements to be of XML built-in type gMonthDay. This relationship was defined on the package in the file package-info.java. Field shipDate in file TrackingOrder is also defined to be of type XMLGregorianCalendar, but the @XmlSchemaType annotation statements override the package definition and specify the field to be of type date. Property method getTrackingDuration defines the schema element to be defined as primitive type duration and not Java type String.

Building and Running the XmlSchemaType Class Example Using NetBeans IDE

Follow these instructions to build and run the XmlSchemaType Class example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlSchemaType-class folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlSchemaType-class project and select Run.

Building and Running the XmlSchemaType Class Example Using Ant

To compile and run the XmlSchemaType Class example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlSchemaType-class/ directory and type the following:


ant runapp

XmlType Example

The XmlType example demonstrates the use of the @XmlType annotation. The @XmlType annotation maps a class or an enum type to a XML Schema type.

A class must have either a public zero-argument constructor or a static zero-argument factory method in order to be mapped by this annotation. One of these methods is used during unmarshalling to create an instance of the class. The factory method may reside within in a factory class or the existing class.

There is an order of precedence as to which method is used for unmarshalling:

In this example, a factory class provides zero arg factory methods for several classes. The @XmlType annotation on class OrderContext references the factory class. The unmarshaller will use the identified factory method in this class.

public class OrderFormsFactory {
    public OrderContext newOrderInstance() {
        return new OrderContext()
    }
    public PurchaseOrderType newPurchaseOrderType() {
        return new newPurchaseOrderType();
    }
}
@XmlType(name="oContext", factoryClass="OrderFormsFactory",
  factoryMethod="newOrderInstance")
public class OrderContext {
    public OrderContext(){ ..... }
}

In this example, a factory method is defined in a class, which also contains a standard class construct. Because the factoryMethod value is defined and no factoryClass is defined, the factory method newOrderInstance is used during unmarshalling.

@XmlType(name="oContext", factoryMethod="newOrderInstance")
 public class OrderContext {
    public OrderContext(){ ..... }
    public OrderContext newOrderInstance() {
         return new OrderContext();
    }
}

Building and Running the XmlType Example Using NetBeans IDE

Follow these instructions to build and run the XmlType example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jaxb/.

  3. Select the j2s-xmlType folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. Right-click the j2s-xmlType project and select Run.

Building and Running the XmlType Example Using Ant

To compile and run the XmlType example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/jaxb/j2s-xmlType/ directory and type the following:


ant runapp

Further Information about JAXB

For more information about JAXB, XML, and XML Schema, see:

Chapter 18 Streaming API for XML

This chapter focuses on the Streaming API for XML (StAX), a streaming Java-based, event-driven, pull-parsing API for reading and writing XML documents. StAX enables you to create bidrectional XML parsers that are fast, relatively easy to program, and have a light memory footprint.

StAX is the latest API in the JAXP family, and provides an alternative to SAX, DOM, TrAX, and DOM for developers looking to do high-performance stream filtering, processing, and modification, particularly with low memory and limited extensibility requirements.

To summarize, StAX provides a standard, bidirectional pull parser interface for streaming XML processing, offering a simpler programming model than SAX and more efficient memory management than DOM. StAX enables developers to parse and modify XML streams as events, and to extend XML information models to allow application-specific additions. More detailed comparisons of StAX with several alternative APIs are provided below, in Comparing StAX to Other JAXP APIs.

Why StAX?

The StAX project was spearheaded by BEA with support from Sun Microsystems, and the JSR 173 specification passed the Java Community Process final approval ballot in March, 2004 (http://jcp.org/en/jsr/detail?id=173). The primary goal of the StAX API is to give “parsing control to the programmer by exposing a simple iterator based API. This allows the programmer to ask for the next event (pull the event) and allows state to be stored in procedural fashion.” StAX was created to address limitations in the two most prevalent parsing APIs, SAX and DOM.

Streaming versus DOM

Generally speaking, there are two programming models for working with XML infosets: streaming and the document object model (DOM).

The DOM model involves creating in-memory objects representing an entire document tree and the complete infoset state for an XML document. Once in memory, DOM trees can be navigated freely and parsed arbitrarily, and as such provide maximum flexibility for developers. However, the cost of this flexibility is a potentially large memory footprint and significant processor requirements, because the entire representation of the document must be held in memory as objects for the duration of the document processing. This may not be an issue when working with small documents, but memory and processor requirements can escalate quickly with document size.

Streaming refers to a programming model in which XML infosets are transmitted and parsed serially at application runtime, often in real time, and often from dynamic sources whose contents are not precisely known beforehand. Moreover, stream-based parsers can start generating output immediately, and infoset elements can be discarded and garbage collected immediately after they are used. While providing a smaller memory footprint, reduced processor requirements, and higher performance in certain situations, the primary trade-off with stream processing is that you can only see the infoset state at one location at a time in the document. You are essentially limited to the “cardboard tube” view of a document, the implication being that you need to know what processing you want to do before reading the XML document.

Streaming models for XML processing are particularly useful when your application has strict memory limitations, as with a cell phone running J2ME, or when your application needs to simultaneously process several requests, as with an application server. In fact, it can be argued that the majority of XML business logic can benefit from stream processing, and does not require the in-memory maintenance of entire DOM trees.

Pull Parsing versus Push Parsing

Streaming pull parsing refers to a programming model in which a client application calls methods on an XML parsing library when it needs to interact with an XML infoset; that is, the client only gets (pulls) XML data when it explicitly asks for it.

Streaming push parsing refers to a programming model in which an XML parser sends (pushes) XML data to the client as the parser encounters elements in an XML infoset; that is, the parser sends the data whether or not the client is ready to use it at that time.

Pull parsing provides several advantages over push parsing when working with XML streams:

StAX Use Cases

The StAX specification defines a number of use cases for the API:

A complete discussion of all these use cases is beyond the scope of this chapter. Please refer to the StAX specification for further information.

Comparing StAX to Other JAXP APIs

As an API in the JAXP family, StAX can be compared, among other APIs, to SAX, TrAX, and JDOM. Of the latter two, StAX is not as powerful or flexible as TrAX or JDOM, but neither does it require as much memory or processor load to be useful, and StAX can, in many cases, outperform the DOM-based APIs. The same arguments outlined above, weighing the cost/benefits of the DOM model versus the streaming model, apply here.

With this in mind, the closest comparisons can be made between StAX and SAX, and it is here that StAX offers features that are beneficial in many cases; some of these include:

Table 18–1 summarizes the comparative features of StAX, SAX, DOM, and TrAX (table adapted from “Does StAX Belong in Your XML Toolbox?” at http://www.developer.com/xml/article.php/3397691 by Jeff Ryan).

Table 18–1 XML Parser API Feature Summary

Feature 

StAX 

SAX 

DOM 

TrAX 

API Type 

Pull, streaming 

Push, streaming 

In memory tree 

XSLT Rule 

Ease of Use 

High 

Medium 

High 

Medium 

XPath Capability 

Not supported 

Not supported 

Supported 

Supported 

CPU and Memory Efficiency 

Good 

Good 

Varies 

Varies 

Forward Only 

Supported 

Supported 

Not supported 

Not supported 

Read XML 

Supported 

Supported 

Supported 

Supported 

Write XML 

Supported 

Not supported 

Supported 

Supported 

Create, Read, Update, Delete 

Not supported 

Not supported 

Supported 

Not supported 

StAX API

The StAX API exposes methods for iterative, event-based processing of XML documents. XML documents are treated as a filtered series of events, and infoset states can be stored in a procedural fashion. Moreover, unlike SAX, the StAX API is bidirectional, enabling both reading and writing of XML documents.

The StAX API is really two distinct API sets: a cursor API and an iterator API. These two API sets explained in greater detail later in this chapter, but their main features are briefly described below.

Cursor API

As the name implies, the StAX cursor API represents a cursor with which you can walk an XML document from beginning to end. This cursor can point to one thing at a time, and always moves forward, never backward, usually one infoset element at a time.

The two main cursor interfaces are XMLStreamReader and XMLStreamWriter. XMLStreamReader includes accessor methods for all possible information retrievable from the XML Information model, including document encoding, element names, attributes, namespaces, text nodes, start tags, comments, processing instructions, document boundaries, and so forth; for example:

public interface XMLStreamReader {
    public int next() throws XMLStreamException;
    public boolean hasNext() throws XMLStreamException;
    public String getText();
    public String getLocalName();
    public String getNamespaceURI();
    // ... other methods not shown
}

You can call methods on XMLStreamReader, such as getText and getName, to get data at the current cursor location. XMLStreamWriter provides methods that correspond to StartElement and EndElement event types; for example:

public interface XMLStreamWriter {
    public void writeStartElement(String localName) 
        throws XMLStreamException;
    public void writeEndElement() 
        throws XMLStreamException;
    public void writeCharacters(String text) 
        throws XMLStreamException;
// ... other methods not shown
}

The cursor API mirrors SAX in many ways. For example, methods are available for directly accessing string and character information, and integer indexes can be used to access attribute and namespace information. As with SAX, the cursor API methods return XML information as strings, which minimizes object allocation requirements.

Iterator API

The StAX iterator API represents an XML document stream as a set of discrete event objects. These events are pulled by the application and provided by the parser in the order in which they are read in the source XML document.

The base iterator interface is called XMLEvent, and there are subinterfaces for each event type listed in Table 18–2. The primary parser interface for reading iterator events is XMLEventReader, and the primary interface for writing iterator events is XMLEventWriter. The XMLEventReader interface contains five methods, the most important of which is nextEvent, which returns the next event in an XML stream. XMLEventReader implements java.util.Iterator, which means that returns from XMLEventReader can be cached or passed into routines that can work with the standard Java Iterator; for example:

public interface XMLEventReader extends Iterator {
    public XMLEvent nextEvent() throws XMLStreamException;
    public boolean hasNext();
    public XMLEvent peek() throws XMLStreamException;
    ...
}

Similarly, on the output side of the iterator API, you have:

public interface XMLEventWriter {
    public void flush() throws XMLStreamException;
    public void close() throws XMLStreamException;
    public void add(XMLEvent e) throws XMLStreamException;
    public void add(Attribute attribute) throws XMLStreamException;
    ...
}

Iterator Event Types

Table 18–2 lists the XMLEvent types defined in the event iterator API.

Table 18–2 XMLEvent Types

Event Type 

Description 

StartDocument

Reports the beginning of a set of XML events, including encoding, XML version, and standalone properties. 

StartElement

Reports the start of an element, including any attributes and namespace declarations; also provides access to the prefix, namespace URI, and local name of the start tag. 

EndElement

Reports the end tag of an element. Namespaces that have gone out of scope can be recalled here if they have been explicitly set on their corresponding StartElement.

Characters

Corresponds to XML CData sections and CharacterData entities. Note that ignorable white space and significant white space are also reported as Character events.

EntityReference

Character entities can be reported as discrete events, which an application developer can then choose to resolve or pass through unresolved. By default, entities are resolved. Alternatively, if you do not want to report the entity as an event, replacement text can be substituted and reported as Characters.

ProcessingInstruction

Reports the target and data for an underlying processing instruction. 

Comment

Returns the text of a comment. 

EndDocument

Reports the end of a set of XML events. 

DTD

Reports as java.lang.String information about the DTD, if any, associated with the stream, and provides a method for returning custom objects found in the DTD.

Attribute

Attributes are generally reported as part of a StartElement event. However, there are times when it is desirable to return an attribute as a standalone Attribute event; for example, when a namespace is returned as the result of an XQuery or XPath expression.

Namespace

As with attributes, namespaces are usually reported as part of a StartElement, but there are times when it is desirable to report a namespace as a discrete Namespace event.

Note that the DTD, EntityDeclaration, EntityReference, NotationDeclaration, and ProcessingInstruction events are only created if the document being processed contains a DTD.

Example of Event Mapping

As an example of how the event iterator API maps an XML stream, consider the following XML document:

<?xml version="1.0"?>
<BookCatalogue xmlns="http://www.publishing.org">
    <Book>
        <Title>Yogasana Vijnana: the Science of Yoga</Title>
        <ISBN>81-40-34319-4</ISBN>
        <Cost currency="INR">11.50</Cost>
    </Book>
</BookCatalogue>

This document would be parsed into eighteen primary and secondary events, as shown in Table 18–3. Note that secondary events, shown in curly braces ({}), are typically accessed from a primary event rather than directly.

Table 18–3 Example of Iterator API Event Mapping

Element/Attribute 

Event 

version="1.0"

StartDocument

isCData = false
data = "\n"
IsWhiteSpace = true

Characters

qname = BookCatalogue:http://www.publishing.org
attributes = null
namespaces = {BookCatalogue" -> http://www.publishing.org"}

StartElement

qname = Book
attributes = null
namespaces = null

StartElement

qname = Title
attributes = null
namespaces = null

StartElement

isCData = false
data = "Yogasana Vijnana: the Science of Yoga\n\t"
IsWhiteSpace = false

Characters

qname = Title
namespaces = null

EndElement

qname = ISBN
attributes = null
namespaces = null

StartElement

isCData = false
data = "81-40-34319-4\n\t"
IsWhiteSpace = false

Characters

10 

qname = ISBN
namespaces = null

EndElement

11 

qname = Cost
attributes = {"currency" -> INR}
namespaces = null

StartElement

12 

isCData = false
data = "11.50\n\t"
IsWhiteSpace = false

Characters

13 

qname = Cost
namespaces = null

EndElement

14 

isCData = false
data = "\n"
IsWhiteSpace = true

Characters

15 

qname = Book
namespaces = null

EndElement

16 

isCData = false
data = "\n"
IsWhiteSpace = true

Characters

17 

qname = BookCatalogue:http://www.publishing.org
namespaces = {BookCatalogue" -> http://www.publishing.org"}

EndElement

18 

 

EndDocument

There are several important things to note in this example:

Choosing between Cursor and Iterator APIs

It is reasonable to ask at this point, “What API should I choose? Should I create instances of XMLStreamReader or XMLEventReader? Why are there two kinds of APIs anyway?”

Development Goals

The authors of the StAX specification targeted three types of developers:

Given these wide-ranging development categories, the StAX authors felt it was more useful to define two small, efficient APIs rather than overloading one larger and necessarily more complex API.

Comparing Cursor and Iterator APIs

Before choosing between the cursor and iterator APIs, you should note a few things that you can do with the iterator API that you cannot do with cursor API:

Similarly, keep some general recommendations in mind when making your choice:

Using StAX

In general, StAX programmers create XML stream readers, writers, and events by using the XMLInputFactory, XMLOutputFactory, and XMLEventFactory classes. Configuration is done by setting properties on the factories, whereby implementation-specific settings can be passed to the underlying implementation using the setProperty method on the factories. Similarly, implementation-specific settings can be queried using the getProperty factory method.

The XMLInputFactory, XMLOutputFactory, and XMLEventFactory classes are described below, followed by discussions of resource allocation, namespace and attribute management, error handling, and then finally reading and writing streams using the cursor and iterator APIs.

StAX Factory Classes

The StAX factory classes. XMLInputFactory, XMLOutputFactory, and XMLEventFactory, let you define and configure implementation instances of XML stream reader, stream writer, and event classes.

XMLInputFactory Class

The XMLInputFactory class lets you configure implementation instances of XML stream reader processors created by the factory. New instances of the abstract class XMLInputFactory are created by calling the newInstance method on the class. The static method XMLInputFactory.newInstance is then used to create a new factory instance.

    Deriving from JAXP, the XMLInputFactory.newInstance method determines the specific XMLInputFactory implementation class to load by using the following lookup procedure:

  1. Use the javax.xml.stream.XMLInputFactory system property.

  2. Use the lib/xml.stream.properties file in the J2SE Java Runtime Environment (JRE) directory.

  3. Use the Services API, if available, to determine the classname by looking in the META-INF/services/javax.xml.stream.XMLInputFactory files in JAR files available to the JRE.

  4. Use the platform default XMLInputFactory instance.

After getting a reference to an appropriate XMLInputFactory, an application can use the factory to configure and create stream instances. Table 18–4 lists the properties supported by XMLInputFactory. See the StAX specification for a more detailed listing.

Table 18–4 javax.xml.stream.XMLInputFactory Properties

Property 

Description 

isValidating

Turns on implementation-specific validation. 

isCoalescing

(Required) Requires the processor to coalesce adjacent character data.

isNamespaceAware

Turns off namespace support. All implementations must support namespaces. Support for non-namespace-aware documents is optional. 

isReplacingEntityReferences

(Required) Requires the processor to replace internal entity references with their replacement value and report them as characters or the set of events that describe the entity.

isSupportingExternalEntities

(Required) Requires the processor to resolve external parsed entities.

reporter

(Required) Sets and gets the implementation of the XMLReporter interface.

resolver

(Required) Sets and gets the implementation of the XMLResolver interface.

allocator

(Required) Sets and gets the implementation of the XMLEventAllocator interface.

XMLOutputFactory Class

New instances of the abstract class XMLOutputFactory are created by calling the newInstance method on the class. The static method XMLOutputFactory.newInstance is then used to create a new factory instance. The algorithm used to obtain the instance is the same as for XMLInputFactory but references the javax.xml.stream.XMLOutputFactory system property.

XMLOutputFactory supports only one property, javax.xml.stream.isRepairingNamespaces. This property is required, and its purpose is to create default prefixes and associate them with Namespace URIs. See the StAX specification for more information.

XMLEventFactory Class

New instances of the abstract class XMLEventFactory are created by calling the newInstance method on the class. The static method XMLEventFactory.newInstance is then used to create a new factory instance. This factory references the javax.xml.stream.XMLEventFactory property to instantiate the factory. The algorithm used to obtain the instance is the same as for XMLInputFactory and XMLOutputFactory but references the javax.xml.stream.XMLEventFactory system property.

There are no default properties for XMLEventFactory.

Resources, Namespaces, and Errors

The StAX specification handles resource resolution, attributes and namespace, and errors and exceptions as described below.

Resource Resolution

The XMLResolver interface provides a means to set the method that resolves resources during XML processing. An application sets the interface on XMLInputFactory, which then sets the interface on all processors created by that factory instance.

Attributes and Namespaces

Attributes are reported by a StAX processor using lookup methods and strings in the cursor interface, and Attribute and Namespace events in the iterator interface. Note here that namespaces are treated as attributes, although namespaces are reported separately from attributes in both the cursor and iterator APIs. Note also that namespace processing is optional for StAX processors. See the StAX specification for complete information about namespace binding and optional namespace processing.

Error Reporting and Exception Handling

All fatal errors are reported by way of the javax.xml.stream.XMLStreamException interface. All nonfatal errors and warnings are reported using the javax.xml.stream.XMLReporter interface.

Reading XML Streams

As described earlier in this chapter, the way you read XML streams with a StAX processor, and what you get back, vary significantly depending on whether you are using the StAX cursor API or the event iterator API. The following two sections describe how to read XML streams with each of these APIs.

Using XMLStreamReader

The XMLStreamReader interface in the StAX cursor API lets you read XML streams or documents in a forward direction only, one item in the infoset at a time. The following methods are available for pulling data from the stream or skipping unwanted events:

Instances of XMLStreamReader have at any one time a single current event on which its methods operate. When you create an instance of XMLStreamReader on a stream, the initial current event is the START_DOCUMENT state. The XMLStreamReader.next method can then be used to step to the next event in the stream.

Reading Properties, Attributes, and Namespaces

The XMLStreamReader.next method loads the properties of the next event in the stream. You can then access those properties by calling the XMLStreamReader.getLocalName and XMLStreamReader.getText methods.

When the XMLStreamReader cursor is over a StartElement event, it reads the name and any attributes for the event, including the namespace. All attributes for an event can be accessed using an index value, and can also be looked up by namespace URI and local name. Note, however, that only the namespaces declared on the current StartEvent are available; previously declared namespaces are not maintained, and redeclared namespaces are not removed.

XMLStreamReader Methods

XMLStreamReader provides the following methods for retrieving information about namespaces and attributes:

int getAttributeCount();
String getAttributeNamespace(int index);
String getAttributeLocalName(int index);
String getAttributePrefix(int index);
String getAttributeType(int index);
String getAttributeValue(int index);
String getAttributeValue(String namespaceUri, String localName);
boolean isAttributeSpecified(int index);

Namespaces can also be accessed using three additional methods:

int getNamespaceCount();
String getNamespacePrefix(int index);
String getNamespaceURI(int index);

Instantiating an XMLStreamReader

This example, taken from the StAX specification, shows how to instantiate an input factory, create a reader, and iterate over the elements of an XML stream:

XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader r = f.createXMLStreamReader( ... );
while(r.hasNext()) {
    r.next();
}

Using XMLEventReader

The XMLEventReader API in the StAX event iterator API provides the means to map events in an XML stream to allocated event objects that can be freely reused, and the API itself can be extended to handle custom events.

XMLEventReader provides four methods for iteratively parsing XML streams:

For example, the following code snippet illustrates the XMLEventReader method declarations:

package javax.xml.stream;
import java.util.Iterator;
public interface XMLEventReader extends Iterator {
    public Object next();
    public XMLEvent nextEvent() throws XMLStreamException;
    public boolean hasNext();
    public XMLEvent peek() throws XMLStreamException;
    ...
}

To read all events on a stream and then print them, you could use the following:

while(stream.hasNext()) {
    XMLEvent event = stream.nextEvent();
    System.out.print(event);
}

Reading Attributes

You can access attributes from their associated javax.xml.stream.StartElement, as follows:

public interface StartElement extends XMLEvent {
    public Attribute getAttributeByName(QName name);
    public Iterator getAttributes();
}

You can use the getAttributes method on the StartElement interface to use an Iterator over all the attributes declared on that StartElement.

Reading Namespaces

Similar to reading attributes, namespaces are read using an Iterator created by calling the getNamespaces method on the StartElement interface. Only the namespace for the current StartElement is returned, and an application can get the current namespace context by using StartElement.getNamespaceContext.

Writing XML Streams

StAX is a bidirectional API, and both the cursor and event iterator APIs have their own set of interfaces for writing XML streams. As with the interfaces for reading streams, there are significant differences between the writer APIs for cursor and event iterator. The following sections describe how to write XML streams using each of these APIs.

Using XMLStreamWriter

The XMLStreamWriter interface in the StAX cursor API lets applications write back to an XML stream or create entirely new streams. XMLStreamWriter has methods that let you:

Note that XMLStreamWriter implementations are not required to perform well-formedness or validity checks on input. While some implementations may perform strict error checking, others may not. The rules you implement are applied to properties defined in the XMLOutputFactory class.

The writeCharacters method is used to escape characters such as &, <, >, and ". Binding prefixes can be handled by either passing the actual value for the prefix, by using the setPrefix method, or by setting the property for defaulting namespace declarations.

The following example, taken from the StAX specification, shows how to instantiate an output factory, create a writer, and write XML output:

XMLOutputFactory output = XMLOutputFactory.newInstance();
XMLStreamWriter writer = output.createXMLStreamWriter( ... );
writer.writeStartDocument();
writer.setPrefix("c","http://c");
writer.setDefaultNamespace("http://c");
writer.writeStartElement("http://c","a");
writer.writeAttribute("b","blah");
writer.writeNamespace("c","http://c");
writer.writeDefaultNamespace("http://c");
writer.setPrefix("d","http://c");
writer.writeEmptyElement("http://c","d");
writer.writeAttribute("http://c","chris","fry");
writer.writeNamespace("d","http://c");
writer.writeCharacters("Jean Arp");
writer.writeEndElement();
writer.flush();

This code generates the following XML (new lines are non-normative):

<?xml version=’1.0’ encoding=’utf-8’?>
<a b="blah" xmlns:c="http://c" xmlns="http://c">
<d:d d:chris="fry" xmlns:d="http://c"/>Jean Arp</a>

Using XMLEventWriter

The XMLEventWriter interface in the StAX event iterator API lets applications write back to an XML stream or create entirely new streams. This API can be extended, but the main API is as follows:

public interface XMLEventWriter {
    public void flush() throws XMLStreamException;
    public void close() throws XMLStreamException;
    public void add(XMLEvent e) throws XMLStreamException;
    // ... other methods not shown.
}

Instances of XMLEventWriter are created by an instance of XMLOutputFactory. Stream events are added iteratively, and an event cannot be modified after it has been added to an event writer instance.

Attributes, Escaping Characters, Binding Prefixes

StAX implementations are required to buffer the last StartElement until an event other than Attribute or Namespace is added or encountered in the stream. This means that when you add an Attribute or a Namespace to a stream, it is appended the current StartElement event.

You can use the Characters method to escape characters like &, <, >, and ".

The setPrefix(...) method can be used to explicitly bind a prefix for use during output, and the getPrefix(...) method can be used to get the current prefix. Note that by default, XMLEventWriter adds namespace bindings to its internal namespace map. Prefixes go out of scope after the corresponding EndElement for the event in which they are bound.

Sun’s Streaming XML Parser Implementation

Application Server includes Sun Microsystems’ JSR 173 (StAX) implementation, called the Sun Java Streaming XML Parser (referred to as Streaming XML Parser). The Streaming XML Parser is a high-speed, non-validating, W3C XML 1.0 and Namespace 1.0-compliant streaming XML pull parser built upon the Xerces2 codebase.

In Sun’s Streaming XML Parser implementation, the Xerces2 lower layers, particularly the Scanner and related classes, have been redesigned to behave in a pull fashion. In addition to the changes in the lower layers, the Streaming XML Parser includes additional StAX-related functionality and many performance-enhancing improvements. The Streaming XML Parser is implemented in the appserv-ws.jar and javaee.jar files, both of which are located in the as-install/lib/ directory.

Included with this Java EE tutorial are StAX code examples, located in the tut-install/javaeetutorial5/examples/stax/ directory, that illustrate how Sun’s Streaming XML Parser implementation works. These examples are described in Example Code.

Before you proceed with the example code, there are two aspects of the Streaming XML Parser of which you should be aware:

These topics are discussed below.

Reporting CDATA Events

The javax.xml.stream.XMLStreamReader implemented in the Streaming XML Parser does not report CDATA events. If you have an application that needs to receive such events, configure the XMLInputFactory to set the following implementation-specific report-cdata-event property:

XMLInputFactory factory = XMLInptuFactory.newInstance();
factory.setProperty("report-cdata-event", Boolean.TRUE);

Streaming XML Parser Factories Implementation

Most applications do not need to know the factory implementation class name. Just adding the javaee.jar and appserv-ws.jar files to the classpath is sufficient for most applications because these two jars supply the factory implementation classname for various Streaming XML Parser properties under the META-INF/services/ directory (for example, javax.xml.stream.XMLInputFactory, javax.xml.stream.XMLOutputFactory, and javax.xml.stream.XMLEventFactory).

However, there may be scenarios when an application would like to know about the factory implementation class name and set the property explicitly. These scenarios could include cases where there are multiple JSR 173 implementations in the classpath and the application wants to choose one, perhaps one that has superior performance, contains a crucial bug fix, or suchlike.

If an application sets the SystemProperty, it is the first step in a lookup operation, and so obtaining the factory instance would be fast compared to other options; for example:

javax.xml.stream.XMLInputFactory -->
     com.sun.xml.stream.ZephyrParserFactory
javax.xml.stream.XMLOutputFactory -->
     com.sun.xml.stream.ZephyrWriterFactor
javax.xml.stream.XMLEventFactory -->
     com.sun.xml.stream.events.ZephyrEventFactory

Example Code

This section steps through the example StAX code included in the Java EE 5 Tutorial bundle. All example directories used in this section are located in the tut-install/javaeetutorial5/examples/stax/ directory.

The topics covered in this section are as follows:

Example Code Organization

The tut-install/javaeetutorial5/examples/stax/ directory contains the six StAX example directories:

All of the StAX examples except for the Writer example use an example XML document, BookCatalog.xml.

Example XML Document

The example XML document, BookCatalog.xml, used by most of the StAX example classes, is a simple book catalog based on the common BookCatalogue namespace. The contents of BookCatalog.xml are listed below:

<?xml version="1.0" encoding="UTF-8"?>
<BookCatalogue xmlns="http://www.publishing.org">
    <Book>
        <Title>Yogasana Vijnana: the Science of Yoga</Title>
        <author>Dhirendra Brahmachari</Author>
        <Date>1966</Date>
        <ISBN>81-40-34319-4</ISBN>
        <Publisher>Dhirendra Yoga Publications</Publisher>
        <Cost currency="INR">11.50</Cost>
    </Book>
    <Book>
        <Title>The First and Last Freedom</Title>
        <Author>J. Krishnamurti</Author>
        <Date>1954</Date>
        <ISBN>0-06-064831-7</ISBN>
        <Publisher>Harper &amp; Row</Publisher>
        <Cost currency="USD">2.95</Cost>
    </Book>
</BookCatalogue>

Cursor Example

Located in the tut-install/javaeetutorial5/examples/stax/cursor/ directory, CursorParse.java demonstrates using the StAX cursor API to read an XML document. In the Cursor example, the application instructs the parser to read the next event in the XML input stream by calling <code>next()</code>.

Note that <code>next()</code> just returns an integer constant corresponding to underlying event where the parser is positioned. The application needs to call the relevant function to get more information related to the underlying event.

You can imagine this approach as a virtual cursor moving across the XML input stream. There are various accessor methods which can be called when that virtual cursor is at a particular event.

Stepping through Events

In this example, the client application pulls the next event in the XML stream by calling the next method on the parser; for example:

try {
    for (int i = 0 ; i < count ; i++) {
        // pass the file name.. all relative entity
        // references will be resolved against this as
        // base URI.
        XMLStreamReader xmlr =
            xmlif.createXMLStreamReader(filename,
                new FileInputStream(filename));
        // when XMLStreamReader is created, it is positioned
        // at START_DOCUMENT event.
        int eventType = xmlr.getEventType();
        printEventType(eventType);
        printStartDocument(xmlr);
        // check if there are more events in the input stream
        while(xmlr.hasNext()) {
            eventType = xmlr.next();
            printEventType(eventType);
            // these functions print the information about
            // the particular event by calling the relevant
            // function
            printStartElement(xmlr);
            printEndElement(xmlr);
            printText(xmlr);
            printPIData(xmlr);
            printComment(xmlr);
        }
    }
}

Note that next just returns an integer constant corresponding to the event underlying the current cursor location. The application calls the relevant function to get more information related to the underlying event. There are various accessor methods which can be called when the cursor is at particular event.

Returning String Representations

Because the next method only returns integers corresponding to underlying event types, you typically need to map these integers to string representations of the events; for example:

public final static String getEventTypeString(int eventType) {
    switch (eventType) {
        case XMLEvent.START_ELEMENT:
            return "START_ELEMENT";
        case XMLEvent.END_ELEMENT:
            return "END_ELEMENT";
        case XMLEvent.PROCESSING_INSTRUCTION:
            return "PROCESSING_INSTRUCTION";
        case XMLEvent.CHARACTERS:
            return "CHARACTERS";
        case XMLEvent.COMMENT:
            return "COMMENT";
        case XMLEvent.START_DOCUMENT:
            return "START_DOCUMENT";
        case XMLEvent.END_DOCUMENT:
            return "END_DOCUMENT";
        case XMLEvent.ENTITY_REFERENCE:
            return "ENTITY_REFERENCE";
        case XMLEvent.ATTRIBUTE:
            return "ATTRIBUTE";
        case XMLEvent.DTD:
            return "DTD";
        case XMLEvent.CDATA:
            return "CDATA";
        case XMLEvent.SPACE:
            return "SPACE";
    }
    return "UNKNOWN_EVENT_TYPE , " + eventType;
}

Building and Running the Cursor Example Using NetBeans IDE

    Follow these instructions to build and run the Cursor example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the cursor folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the cursor project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    -x 1 BookCatalog.xml
    
  8. Click OK.

  9. Right-click the cursor project and select Run.

Building and Running the Cursor Example Using Ant

To compile and run the Cursor example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/cursor/ directory and type the following:


ant run-cursor

Cursor-to-Event Example

Located in the tut-install/javaeetutorial5/examples/stax/cursor2event/ directory, CursorApproachEventObject.java demonstrates how to get information returned by an XMLEvent object even when using the cursor API.

The idea here is that the cursor API’s XMLStreamReader returns integer constants corresponding to particular events, while the event iterator API’s XMLEventReader returns immutable and persistent event objects. XMLStreamReader is more efficient, but XMLEventReader is easier to use, because all the information related to a particular event is encapsulated in a returned XMLEvent object. However, the disadvantage of event approach is the extra overhead of creating objects for every event, which consumes both time and memory.

With this mind, XMLEventAllocator can be used to get event information as an XMLEvent object, even when using the cursor API.

Instantiating an XMLEventAllocator

The first step is to create a new XMLInputFactory and instantiate an XMLEventAllocator:

XMLInputFactory xmlif = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + xmlif);
xmlif.setEventAllocator(new XMLEventAllocatorImpl());
allocator = xmlif.getEventAllocator();
XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename,
    new FileInputStream(filename));

Creating an Event Iterator

The next step is to create an event iterator:

int eventType = xmlr.getEventType();
while(xmlr.hasNext()){
    eventType = xmlr.next();
    //Get all "Book" elements as XMLEvent object
    if(eventType == XMLStreamConstants.START_ELEMENT &&
        xmlr.getLocalName().equals("Book")){
        //get immutable XMLEvent
        StartElement event = getXMLEvent(xmlr).asStartElement();
        System.out.println("EVENT: " + event.toString());
    }
}

Creating the Allocator Method

The final step is to create the XMLEventAllocator method:

private static XMLEvent getXMLEvent(XMLStreamReader reader)
         throws XMLStreamException {
    return allocator.allocate(reader);
}

Building and Running the Cursor-to-Event Example Using NetBeans IDE

    Follow these instructions to build and run the Cursor-to-Event example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the cursor2event folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the cursor2event project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    BookCatalog.xml
    
  8. Click OK.

  9. Right-click the cursor2event project and select Run.

    Note how the Book events are returned as strings.

Building and Running the Cursor-to-Event Example Using Ant

To compile and run the Cursor-to-Event example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/cursor2event/ directory and type the following:


ant run-cursor2event

Event Example

Located in the tut-install/javaeetutorial5/examples/stax/event/ directory, EventParse.java demonstrates how to use the StAX event API to read an XML document.

Creating an Input Factory

The first step is to create a new instance of XMLInputFactory:

XMLInputFactory factory = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + factory);

Creating an Event Reader

The next step is to create an instance of XMLEventReader:

XMLEventReader r = factory.createXMLEventReader(filename,
     new FileInputStream(filename));

Creating an Event Iterator

The third step is to create an event iterator:

XMLEventReader r = factory.createXMLEventReader(filename,
     new FileInputStream(filename));
while(r.hasNext()) {
    XMLEvent e = r.nextEvent();
    System.out.println(e.toString());
}

Getting the Event Stream

The final step is to get the underlying event stream:

public final static String getEventTypeString(int eventType) {
    switch (eventType) {
        case XMLEvent.START_ELEMENT:
            return "START_ELEMENT";
        case XMLEvent.END_ELEMENT:
            return "END_ELEMENT";
        case XMLEvent.PROCESSING_INSTRUCTION:
            return "PROCESSING_INSTRUCTION";
        case XMLEvent.CHARACTERS:
            return "CHARACTERS";
        case XMLEvent.COMMENT:
            return "COMMENT";
        case XMLEvent.START_DOCUMENT:
            return "START_DOCUMENT";
        case XMLEvent.END_DOCUMENT:
            return "END_DOCUMENT";
        case XMLEvent.ENTITY_REFERENCE:
            return "ENTITY_REFERENCE";
        case XMLEvent.ATTRIBUTE:
            return "ATTRIBUTE";
        case XMLEvent.DTD:
            return "DTD";
        case XMLEvent.CDATA:
            return "CDATA";
        case XMLEvent.SPACE:
            return "SPACE";
    }
    return "UNKNOWN_EVENT_TYPE " + "," + eventType;
}

Returning the Output

When you run the Event example, the EventParse class is compiled, and the XML stream is parsed as events and returned to STDOUT. For example, an instance of the Author element is returned as:

<[’http://www.publishing.org’]::Author>
    Dhirendra Brahmachari
</[’http://www.publishing.org’]::Author>

Note in this example that the event comprises an opening and closing tag, both of which include the namespace. The content of the element is returned as a string within the tags.

Similarly, an instance of the Cost element is returned as:

<[’http://www.publishing.org’]::Cost currency=’INR’>
    11.50
</[’http://www.publishing.org’]::Cost>

In this case, the currency attribute and value are returned in the opening tag for the event.

Building and Running the Event Example Using NetBeans IDE

    Follow these instructions to build and run the Event example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the event folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the event project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    BookCatalog.xml
    
  8. Click OK.

  9. Right-click the event project and select Run.

Building and Running the Event Example Using Ant

To compile and run the Event example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/event/ directory and type the following:


ant run-event

Filter Example

Located in the tut-install/javaeetutorial5/examples/stax/filter/ directory, MyStreamFilter.java demonstrates how to use the StAX stream filter API to filter out events not needed by your application. In this example, the parser filters out all events except StartElement and EndElement.

Implementing the StreamFilter Class

The MyStreamFilter class implements javax.xml.stream.StreamFilter:

public class MyStreamFilter
     implements javax.xml.stream.StreamFilter {

Creating an Input Factory

The next step is to create an instance of XMLInputFactory. In this case, various properties are also set on the factory:

XMLInputFactory xmlif = null ;
try {
    xmlif = XMLInputFactory.newInstance();
    xmlif.setProperty(
        XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,
        Boolean.TRUE);
    xmlif.setProperty(
        XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
        Boolean.FALSE);
    xmlif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE,
        Boolean.TRUE);
    xmlif.setProperty(XMLInputFactory.IS_COALESCING,
        Boolean.TRUE);
} catch (Exception ex) {
    ex.printStackTrace();
}
System.out.println("FACTORY: " + xmlif);
System.out.println("filename = "+ filename);

Creating the Filter

The next step is to instantiate a file input stream and create the stream filter:

FileInputStream fis = new FileInputStream(filename);
                
XMLStreamReader xmlr = xmlif.createFilteredReader(
    xmlif.createXMLStreamReader(fis), new MyStreamFilter());

int eventType = xmlr.getEventType();
printEventType(eventType);
while(xmlr.hasNext()) {
    eventType = xmlr.next();
    printEventType(eventType);
    printName(xmlr,eventType);
    printText(xmlr);
    if (xmlr.isStartElement()) {
        printAttributes(xmlr);
    }
    printPIData(xmlr);
    System.out.println("-----------------------------");
}

Capturing the Event Stream

The next step is to capture the event stream. This is done in basically the same way as in the Event example.

Filtering the Stream

The final step is to filter the stream:

public boolean accept(XMLStreamReader reader) {
    if (!reader.isStartElement() && !reader.isEndElement())
        return false;
    else
        return true;
}

Returning the Output

When you run the Filter example, the MyStreamFilter class is compiled, and the XML stream is parsed as events and returned to STDOUT. For example, an Author event is returned as follows:

EVENT TYPE(1):START_ELEMENT
HAS NAME: Author
HAS NO TEXT
HAS NO ATTRIBUTES
-----------------------------
EVENT TYPE(2):END_ELEMENT
HAS NAME: Author
HAS NO TEXT
-----------------------------

Similarly, a Cost event is returned as follows:

EVENT TYPE(1):START_ELEMENT
HAS NAME: Cost
HAS NO TEXT

HAS ATTRIBUTES:
 ATTRIBUTE-PREFIX:
 ATTRIBUTE-NAMESP: null
ATTRIBUTE-NAME:   currency
ATTRIBUTE-VALUE: USD
ATTRIBUTE-TYPE:  CDATA

-----------------------------
EVENT TYPE(2):END_ELEMENT
HAS NAME: Cost
HAS NO TEXT
-----------------------------

See Iterator API and Reading XML Streams for a more detailed discussion of StAX event parsing.

Building and Running the Filter Example Using NetBeans IDE

    Follow these instructions to build and run the Filter example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the filter folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the filter project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    -f BookCatalog.xml
    
  8. Click OK.

  9. Right-click the filter project and select Run.

Building and Running the Filter Example Using Ant

To compile and run the Filter example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/filter/ directory and type the following:


ant run-filter

Read-and-Write Example

Located in the tut-install/javaeetutorial5/examples/stax/readnwrite/ directory, EventProducerConsumer.java demonstrates how to use a StAX parser simultaneously as both a producer and a consumer.

The StAX XMLEventWriter API extends from the XMLEventConsumer interface, and is referred to as an event consumer. By contrast, XMLEventReader is an event producer. StAX supports simultaneous reading and writing, such that it is possible to read from one XML stream sequentially and simultaneously write to another stream.

The Read-and-Write example shows how the StAX producer/consumer mechanism can be used to read and write simultaneously. This example also shows how a stream can be modified and how new events can be added dynamically and then written to a different stream.

Creating an Event Producer/Consumer

The first step is to instantiate an event factory and then create an instance of an event producer/consumer:

XMLEventFactory m_eventFactory = XMLEventFactory.newInstance();
public EventProducerConsumer() {
}
...
try {
    EventProducerConsumer ms = new EventProducerConsumer();
    
    XMLEventReader reader =
        XMLInputFactory.newInstance().createXMLEventReader(
            new java.io.FileInputStream(args[0]));
    XMLEventWriter writer =
        XMLOutputFactory.newInstance().createXMLEventWriter(
            System.out);

Creating an Iterator

The next step is to create an iterator to parse the stream:

while(reader.hasNext()) {
    XMLEvent event = (XMLEvent)reader.next();
    if (event.getEventType() == event.CHARACTERS) {
        writer.add(ms.getNewCharactersEvent(event.asCharacters()));
    } else {
        writer.add(event);
    }
}
writer.flush();

Creating a Writer

The final step is to create a stream writer in the form of a new Character event:

Characters getNewCharactersEvent(Characters event) {
    if (event.getData().equalsIgnoreCase("Name1")) {
        return m_eventFactory.createCharacters(
            Calendar.getInstance().getTime().toString());
    }
    //else return the same event
    else {
        return event;
    }
}

Returning the Output

When you run the Read-and-Write example, the EventProducerConsumer class is compiled, and the XML stream is parsed as events and written back to STDOUT. The output is the contents of the BookCatalog.xml file described in Example XML Document.

Building and Running the Read-and-Write Example Using NetBeans IDE

    Follow these instructions to build and run the Read-and-Write example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the readnwrite folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the readnwrite project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    BookCatalog.xml
    
  8. Click OK.

  9. Right-click the readnwrite project and select Run.

Building and Running the Read-and-Write Example Using Ant

To compile and run the Read-and-Write example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/readnwrite/ directory and type the following:


ant run-readnwrite

Writer Example

Located in the tut-install/javaeetutorial5/examples/stax/writer/ directory, CursorWriter.java demonstrates how to use the StAX cursor API to write an XML stream.

Creating the Output Factory

The first step is to create an instance of XMLOutputFactory:

XMLOutputFactory xof =  XMLOutputFactory.newInstance();

Creating a Stream Writer

The next step is to create an instance of XMLStreamWriter:

XMLStreamWriter xtw = null;

Writing the Stream

The final step is to write the XML stream. Note that the stream is flushed and closed after the final EndDocument is written:

xtw = xof.createXMLStreamWriter(new FileWriter(fileName));
xtw.writeComment("all elements here are explicitly in the HTML namespace");
xtw.writeStartDocument("utf-8","1.0");
xtw.setPrefix("html", "http://www.w3.org/TR/REC-html40");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","html");
xtw.writeNamespace("html", "http://www.w3.org/TR/REC-html40");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","head");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","title");
xtw.writeCharacters("Frobnostication");
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","body");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","p");
xtw.writeCharacters("Moved to");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","a");
xtw.writeAttribute("href","http://frob.com");
xtw.writeCharacters("here");
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndDocument();
xtw.flush();
xtw.close();

Returning the Output

When you run the Writer example, the CursorWriter class is compiled, and the XML stream is parsed as events and written to a file named dist/CursorWriter-Output:

<!--all elements here are explicitly in the HTML namespace-->
<?xml version="1.0" encoding="utf-8"?>
<html:html xmlns:html="http://www.w3.org/TR/REC-html40">
<html:head>
<html:title>Frobnostication</html:title></html:head>
<html:body>
<html:p>Moved to <html:a href="http://frob.com">here</html:a>
</html:p>
</html:body>
</html:html>

In the actual dist/CursorWriter-Output file, this stream is written without any line breaks; the breaks have been added here to make the listing easier to read. In this example, as with the object stream in the Event example, the namespace prefix is added to both the opening and closing HTML tags. Adding this prefix is not required by the StAX specification, but it is good practice when the final scope of the output stream is not definitively known.

Building and Running the Writer Example Using NetBeans IDE

    Follow these instructions to build and run the Writer example on your Application Server instance using the NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog navigate to the tut-install/javaeetutorial5/examples/stax/ directory.

  3. Select the writer folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

  6. In the Projects tab, right-click the writer project and select Properties. The Project Properties dialog is displayed.

  7. Enter the following in the Arguments field:


    -f dist/CursorWriter-Output
    
  8. Click OK.

  9. Right-click the writer project and select Run.

Building and Running the Writer Example Using Ant

To compile and run the Writer example using Ant, in a terminal window, go to the tut-install/javaeetutorial5/examples/stax/writer/ directory and type the following:


ant run-writer

Further Information about StAX

For more information about StAX, see:

For some useful articles about working with StAX, see:

Chapter 19 SOAP with Attachments API for Java

SOAP with Attachments API for Java (SAAJ) is used mainly for the SOAP messaging that goes on behind the scenes in JAX-WS handlers and JAXR implementations. Secondarily, it is an API that developers can use when they choose to write SOAP messaging applications directly rather than use JAX-WS. The SAAJ API allows you to do XML messaging from the Java platform: By simply making method calls using the SAAJ API, you can read and write SOAP-based XML messages, and you can optionally send and receive such messages over the Internet (some implementations may not support sending and receiving). This chapter will help you learn how to use the SAAJ API.

The SAAJ API conforms to the Simple Object Access Protocol (SOAP) 1.1 and 1.2 specifications and the SOAP with Attachments specification. The SAAJ 1.3 specification defines the javax.xml.soap package, which contains the API for creating and populating a SOAP message. This package has all the API necessary for sending request-response messages. (Request-response messages are explained in SOAPConnection Objects.)


Note –

The javax.xml.messaging package, defined in the Java API for XML Messaging (JAXM) 1.1 specification, is not part of the Java EE platform and is not discussed in this chapter. The JAXM API is available as a separate download from http://java.sun.com/xml/downloads/jaxm.html.


This chapter starts with an overview of messages and connections, giving some of the conceptual background behind the SAAJ API to help you understand why certain things are done the way they are. Next, the tutorial shows you how to use the basic SAAJ API, giving examples and explanations of the commonly used features. The code examples in the last part of the tutorial show you how to build an application. The case study in Chapter 36, The Coffee Break Application includes SAAJ code for both sending and consuming a SOAP message.

Overview of SAAJ

This section presents a high-level view of how SAAJ messaging works and explains concepts in general terms. Its goal is to give you some terminology and a framework for the explanations and code examples that are presented in the tutorial section.

The overview looks at SAAJ from two perspectives: messages and connections.

SAAJ Messages

SAAJ messages follow SOAP standards, which prescribe the format for messages and also specify some things that are required, optional, or not allowed. With the SAAJ API, you can create XML messages that conform to the SOAP 1.1 or 1.2 specification and to the WS-I Basic Profile 1.1 specification simply by making Java API calls.

The Structure of an XML Document

An XML document has a hierarchical structure made up of elements, subelements, subsubelements, and so on. You will notice that many of the SAAJ classes and interfaces represent XML elements in a SOAP message and have the word element or SOAP (or both) in their names.

An element is also referred to as a node. Accordingly, the SAAJ API has the interface Node, which is the base class for all the classes and interfaces that represent XML elements in a SOAP message. There are also methods such as SOAPElement.addTextNode, Node.detachNode, and Node.getValue, which you will see how to use in the tutorial section.

What Is in a Message?

The two main types of SOAP messages are those that have attachments and those that do not.

Messages with No Attachments

The following outline shows the very high-level structure of a SOAP message with no attachments. Except for the SOAP header, all the parts listed are required to be in every SOAP message.

I. SOAP message
    A. SOAP part
        1. SOAP envelope
            a. SOAP header (optional)
            b. SOAP body

The SAAJ API provides the SOAPMessage class to represent a SOAP message, the SOAPPart class to represent the SOAP part, the SOAPEnvelope interface to represent the SOAP envelope, and so on. Figure 19–1 illustrates the structure of a SOAP message with no attachments.

Figure 19–1 SOAPMessage Object with No Attachments

Diagram of SOAPMessage Object with SOAPPart, SOAPEnvelope,
SOAPHeader, and SOAPBody


Note –

Many SAAJ API interfaces extend DOM interfaces. In a SAAJ message, the SOAPPart class is also a DOM document. See SAAJ and DOM for details.


When you create a new SOAPMessage object, it will automatically have the parts that are required to be in a SOAP message. In other words, a new SOAPMessage object has a SOAPPart object that contains a SOAPEnvelope object. The SOAPEnvelope object in turn automatically contains an empty SOAPHeader object followed by an empty SOAPBody object. If you do not need the SOAPHeader object, which is optional, you can delete it. The rationale for having it automatically included is that more often than not you will need it, so it is more convenient to have it provided.

The SOAPHeader object can include one or more headers that contain metadata about the message (for example, information about the sending and receiving parties). The SOAPBody object, which always follows the SOAPHeader object if there is one, contains the message content. If there is a SOAPFault object (see Using SOAP Faults), it must be in the SOAPBody object.

Messages with Attachments

A SOAP message may include one or more attachment parts in addition to the SOAP part. The SOAP part must contain only XML content; as a result, if any of the content of a message is not in XML format, it must occur in an attachment part. So if, for example, you want your message to contain a binary file, your message must have an attachment part for it. Note that an attachment part can contain any kind of content, so it can contain data in XML format as well. Figure 19–2 shows the high-level structure of a SOAP message that has two attachments.

Figure 19–2 SOAPMessage Object with Two AttachmentPart Objects

Diagram of SOAPMessage Object with SOAPPart, SOAPEnvelope,
SOAPHeader, SOAPBody, and two AttachmentParts

The SAAJ API provides the AttachmentPart class to represent an attachment part of a SOAP message. A SOAPMessage object automatically has a SOAPPart object and its required subelements, but because AttachmentPart objects are optional, you must create and add them yourself. The tutorial section walks you through creating and populating messages with and without attachment parts.

If a SOAPMessage object has one or more attachments, each AttachmentPart object must have a MIME header to indicate the type of data it contains. It may also have additional MIME headers to identify it or to give its location. These headers are optional but can be useful when there are multiple attachments. When a SOAPMessage object has one or more AttachmentPart objects, its SOAPPart object may or may not contain message content.

SAAJ and DOM

The SAAJ APIs extend their counterparts in the org.w3c.dom package:

Moreover, the SOAPPart of a SOAPMessage is also a DOM Level 2 Document and can be manipulated as such by applications, tools, and libraries that use DOM. For details on how to use DOM documents with the SAAJ API, see Adding Content to the SOAPPart Object and Adding a Document to the SOAP Body.

SAAJ Connections

All SOAP messages are sent and received over a connection. With the SAAJ API, the connection is represented by a SOAPConnection object, which goes from the sender directly to its destination. This kind of connection is called a point-to-point connection because it goes from one endpoint to another endpoint. Messages sent using the SAAJ API are called request-response messages. They are sent over a SOAPConnection object with the call method, which sends a message (a request) and then blocks until it receives the reply (a response).

SOAPConnection Objects

The following code fragment creates the SOAPConnection object connection and then, after creating and populating the message, uses connection to send the message. As stated previously, all messages sent over a SOAPConnection object are sent with the call method, which both sends the message and blocks until it receives the response. Thus, the return value for the call method is the SOAPMessage object that is the response to the message that was sent. The request parameter is the message being sent; endpoint represents where it is being sent.

SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = factory.createConnection();

. . .// create a request message and give it content

java.net.URL endpoint = new URL("http://fabulous.com/gizmo/order");
SOAPMessage response = connection.call(request, endpoint);

Note that the second argument to the call method, which identifies where the message is being sent, can be a String object or a URL object. Thus, the last two lines of code from the preceding example could also have been the following:

String endpoint = "http://fabulous.com/gizmo/order";
SOAPMessage response = connection.call(request, endpoint);

A web service implemented for request-response messaging must return a response to any message it receives. The response is a SOAPMessage object, just as the request is a SOAPMessage object. When the request message is an update, the response is an acknowledgment that the update was received. Such an acknowledgment implies that the update was successful. Some messages may not require any response at all. The service that gets such a message is still required to send back a response because one is needed to unblock the call method. In this case, the response is not related to the content of the message; it is simply a message to unblock the call method.

Now that you have some background on SOAP messages and SOAP connections, in the next section you will see how to use the SAAJ API.

SAAJ Tutorial

This tutorial walks you through how to use the SAAJ API. First, it covers the basics of creating and sending a simple SOAP message. Then you will learn more details about adding content to messages, including how to create SOAP faults and attributes. Finally, you will learn how to send a message and retrieve the content of the response.

After going through this tutorial, you will know how to perform the following tasks:

In the section Code Examples, you will see the code fragments from earlier parts of the tutorial in runnable applications, which you can test yourself. To see how the SAAJ API can be used in server code, see the SAAJ part of the Coffee Break case study (SAAJ Coffee Supplier Service), which shows an example of both the client and the server code for a web service application.

A SAAJ client can send request-response messages to web services that are implemented to do request-response messaging. This section demonstrates how you can do this.

Creating and Sending a Simple Message

This section covers the basics of creating and sending a simple message and retrieving the content of the response. It includes the following topics:

Creating a Message

The first step is to create a message using a MessageFactory object. The SAAJ API provides a default implementation of the MessageFactory class, thus making it easy to get an instance. The following code fragment illustrates getting an instance of the default message factory and then using it to create a message.

MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();

As is true of the newInstance method for SOAPConnectionFactory, the newInstance method for MessageFactory is static, so you invoke it by calling MessageFactory.newInstance.

If you specify no arguments to the newInstance method, it creates a message factory for SOAP 1.1 messages. To create a message factory that allows you to create and process SOAP 1.2 messages, use the following method call:

MessageFactory factory = 
    MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);

To create a message factory that can create either SOAP 1.1 or SOAP 1.2 messages, use the following method call:

MessageFactory factory =
    MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL);

This kind of factory enables you to process an incoming message that might be of either type.

Parts of a Message

A SOAPMessage object is required to have certain elements, and, as stated previously, the SAAJ API simplifies things for you by returning a new SOAPMessage object that already contains these elements. When you call createMessage with no arguments, the message that is created automatically has the following:

I. A SOAPPart object that contains
    A.  A SOAPEnvelope object that contains
        1.  An empty SOAPHeader object
        2.  An empty SOAPBody object

The SOAPHeader object is optional and can be deleted if it is not needed. However, if there is one, it must precede the SOAPBody object. The SOAPBody object can hold either the content of the message or a fault message that contains status information or details about a problem with the message. The section Using SOAP Faults walks you through how to use SOAPFault objects.

Accessing Elements of a Message

The next step in creating a message is to access its parts so that content can be added. There are two ways to do this. The SOAPMessage object message, created in the preceding code fragment, is the place to start.

The first way to access the parts of the message is to work your way through the structure of the message. The message contains a SOAPPart object, so you use the getSOAPPart method of message to retrieve it:

SOAPPart soapPart = message.getSOAPPart();

Next you can use the getEnvelope method of soapPart to retrieve the SOAPEnvelope object that it contains.

SOAPEnvelope envelope = soapPart.getEnvelope();

You can now use the getHeader and getBody methods of envelope to retrieve its empty SOAPHeader and SOAPBody objects.

SOAPHeader header = envelope.getHeader();
SOAPBody body = envelope.getBody();

The second way to access the parts of the message is to retrieve the message header and body directly, without retrieving the SOAPPart or SOAPEnvelope. To do so, use the getSOAPHeader and getSOAPBody methods of SOAPMessage:

SOAPHeader header = message.getSOAPHeader();
SOAPBody body = message.getSOAPBody();

This example of a SAAJ client does not use a SOAP header, so you can delete it. (You will see more about headers later.) Because all SOAPElement objects, including SOAPHeader objects, are derived from the Node interface, you use the method Node.detachNode to delete header.

header.detachNode();

Adding Content to the Body

The SOAPBody object contains either content or a fault. To add content to the body, you normally create one or more SOAPBodyElement objects to hold the content. You can also add subelements to the SOAPBodyElement objects by using the addChildElement method. For each element or child element, you add content by using the addTextNode method.

When you create any new element, you also need to create an associated javax.xml.namespace.QName object so that it is uniquely identified.


Note –

You can use Name objects instead of QName objects. Name objects are specific to the SAAJ API, and you create them using either SOAPEnvelope methods or SOAPFactory methods. However, the Name interface may be deprecated at a future release.

The SOAPFactory class also lets you create XML elements when you are not creating an entire message or do not have access to a complete SOAPMessage object. For example, JAX-RPC implementations often work with XML fragments rather than complete SOAPMessage objects. Consequently, they do not have access to a SOAPEnvelope object, and this makes using a SOAPFactory object to create Name objects very useful. In addition to a method for creating Name objects, the SOAPFactory class provides methods for creating Detail objects and SOAP fragments. You will find an explanation of Detail objects in Overview of SOAP Faults and Creating and Populating a SOAPFault Object.


QName objects associated with SOAPBodyElement or SOAPHeaderElement objects must be fully qualified; that is, they must be created with a namespace URI, a local part, and a namespace prefix. Specifying a namespace for an element makes clear which one is meant if more than one element has the same local name.

The following code fragment retrieves the SOAPBody object body from message, constructs a QName object for the element to be added, and adds a new SOAPBodyElement object to body.

SOAPBody body = message.getSOAPBody();
QName bodyName = new QName("http://wombat.ztrade.com", "GetLastTradePrice", "m");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

At this point, body contains a SOAPBodyElement object identified by the QName object bodyName, but there is still no content in bodyElement. Assuming that you want to get a quote for the stock of Sun Microsystems, Inc., you need to create a child element for the symbol using the addChildElement method. Then you need to give it the stock symbol using the addTextNode method. The QName object for the new SOAPElement object symbol is initialized with only a local name because child elements inherit the prefix and URI from the parent element.

QName name = new QName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");

You might recall that the headers and content in a SOAPPart object must be in XML format. The SAAJ API takes care of this for you, building the appropriate XML constructs automatically when you call methods such as addBodyElement, addChildElement, and addTextNode. Note that you can call the method addTextNode only on an element such as bodyElement or any child elements that are added to it. You cannot call addTextNode on a SOAPHeader or SOAPBody object because they contain elements and not text.

The content that you have just added to your SOAPBody object will look like the following when it is sent over the wire:

<SOAP-ENV:Envelope
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com">
      <symbol>SUNW</symbol>
    </m:GetLastTradePrice>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Let’s examine this XML excerpt line by line to see how it relates to your SAAJ code. Note that an XML parser does not care about indentations, but they are generally used to indicate element levels and thereby make it easier for a human reader to understand.

Here is the SAAJ code:

SOAPMessage message = messageFactory.createMessage();
SOAPHeader header = message.getSOAPHeader();
SOAPBody body = message.getSOAPBody();

Here is the XML it produces:

<SOAP-ENV:Envelope
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    ...
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The outermost element in this XML example is the SOAP envelope element, indicated by SOAP-ENV:Envelope. Note that Envelope is the name of the element, and SOAP-ENV is the namespace prefix. The interface SOAPEnvelope represents a SOAP envelope.

The first line signals the beginning of the SOAP envelope element, and the last line signals the end of it; everything in between is part of the SOAP envelope. The second line is an example of an attribute for the SOAP envelope element. Because a SOAP envelope element always contains this attribute with this value, a SOAPMessage object comes with it automatically included. xmlns stands for “XML namespace,” and its value is the URI of the namespace associated with Envelope.

The next line is an empty SOAP header. You could remove it by calling header.detachNode after the getSOAPHeader call.

The next two lines mark the beginning and end of the SOAP body, represented in SAAJ by a SOAPBody object. The next step is to add content to the body.

Here is the SAAJ code:

QName bodyName = new QName("http://wombat.ztrade.com",
    "GetLastTradePrice", "m");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

Here is the XML it produces:

<m:GetLastTradePrice
 xmlns:m="http://wombat.ztrade.com">
 ...
</m:GetLastTradePrice>

These lines are what the SOAPBodyElement bodyElement in your code represents. GetLastTradePrice is its local name, m is its namespace prefix, and http://wombat.ztrade.com is its namespace URI.

Here is the SAAJ code:

QName name = new QName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");

Here is the XML it produces:

<symbol>SUNW</symbol>

The String "SUNW" is the text node for the element <symbol>. This String object is the message content that your recipient, the stock quote service, receives.

The following example shows how to add multiple SOAPElement objects and add text to each of them. The code first creates the SOAPBodyElement object purchaseLineItems, which has a fully qualified name associated with it. That is, the QName object for it has a namespace URI, a local name, and a namespace prefix. As you saw earlier, a SOAPBodyElement object is required to have a fully qualified name, but child elements added to it, such as SOAPElement objects, can have Name objects with only the local name.

SOAPBody body = message.getSOAPBody();
QName bodyName = 
    new QName("http://sonata.fruitsgalore.com", "PurchaseLineItems", "PO");
SOAPBodyElement purchaseLineItems =
    body.addBodyElement(bodyName);

QName childName = new QName("Order");
SOAPElement order = purchaseLineItems.addChildElement(childName);

childName = new QName("Product");
SOAPElement product = order.addChildElement(childName);
product.addTextNode("Apple");

childName = new QName("Price");
SOAPElement price = order.addChildElement(childName);
price.addTextNode("1.56");

childName = new QName("Order");
SOAPElement order2 = purchaseLineItems.addChildElement(childName);

childName = new QName("Product");
SOAPElement product2 = order2.addChildElement(childName);
product2.addTextNode("Peach");

childName = soapFactory.new QName("Price");
SOAPElement price2 = order2.addChildElement(childName);
price2.addTextNode("1.48");

The SAAJ code in the preceding example produces the following XML in the SOAP body:

<PO:PurchaseLineItems
 xmlns:PO="http://sonata.fruitsgalore.com">
  <Order>
    <Product>Apple</Product>
    <Price>1.56</Price>
  </Order>

  <Order>
    <Product>Peach</Product>
    <Price>1.48</Price>
  </Order>
</PO:PurchaseLineItems>

Getting a SOAPConnection Object

The SAAJ API is focused primarily on reading and writing messages. After you have written a message, you can send it using various mechanisms (such as JMS or JAXM). The SAAJ API does, however, provide a simple mechanism for request-response messaging.

To send a message, a SAAJ client can use a SOAPConnection object. A SOAPConnection object is a point-to-point connection, meaning that it goes directly from the sender to the destination (usually a URL) that the sender specifies.

The first step is to obtain a SOAPConnectionFactory object that you can use to create your connection. The SAAJ API makes this easy by providing the SOAPConnectionFactory class with a default implementation. You can get an instance of this implementation using the following line of code.

SOAPConnectionFactory soapConnectionFactory =
    SOAPConnectionFactory.newInstance();

Now you can use soapConnectionFactory to create a SOAPConnection object.

SOAPConnection connection = soapConnectionFactory.createConnection();

You will use connection to send the message that you created.

Sending a Message

A SAAJ client calls the SOAPConnection method call on a SOAPConnection object to send a message. The call method takes two arguments: the message being sent and the destination to which the message should go. This message is going to the stock quote service indicated by the URL object endpoint.

java.net.URL endpoint = new URL("http://wombat.ztrade.com/quotes");

SOAPMessage response = connection.call(message, endpoint);

The content of the message you sent is the stock symbol SUNW; the SOAPMessage object response should contain the last stock price for Sun Microsystems, which you will retrieve in the next section.

A connection uses a fair amount of resources, so it is a good idea to close a connection as soon as you are finished using it.

connection.close();

Getting the Content of a Message

The initial steps for retrieving a message’s content are the same as those for giving content to a message: Either you use the Message object to get the SOAPBody object, or you access the SOAPBody object through the SOAPPart and SOAPEnvelope objects.

Then you access the SOAPBody object’s SOAPBodyElement object, because that is the element to which content was added in the example. (In a later section you will see how to add content directly to the SOAPPart object, in which case you would not need to access the SOAPBodyElement object to add content or to retrieve it.)

To get the content, which was added with the method SOAPElement.addTextNode, you call the method Node.getValue. Note that getValue returns the value of the immediate child of the element that calls the method. Therefore, in the following code fragment, the getValue method is called on bodyElement, the element on which the addTextNode method was called.

To access bodyElement, you call the getChildElements method on soapBody. Passing bodyName to getChildElements returns a java.util.Iterator object that contains all the child elements identified by the Name object bodyName. You already know that there is only one, so calling the next method on it will return the SOAPBodyElement you want. Note that the Iterator.next method returns a Java Object, so you need to cast the Object it returns to a SOAPBodyElement object before assigning it to the variable bodyElement.

SOAPBody soapBody = response.getSOAPBody();
java.util.Iterator iterator = soapBody.getChildElements(bodyName);
SOAPBodyElement bodyElement = (SOAPBodyElement)iterator.next();
String lastPrice = bodyElement.getValue();
System.out.print("The last price for SUNW is ");

System.out.println(lastPrice);

If more than one element had the name bodyName, you would have to use a while loop using the Iterator.hasNext method to make sure that you got all of them.

while (iterator.hasNext()) {
    SOAPBodyElement bodyElement = (SOAPBodyElement)iterator.next();
    String lastPrice = bodyElement.getValue();
    System.out.print("The last price for SUNW is ");
    System.out.println(lastPrice);
}

At this point, you have seen how to send a very basic request-response message and get the content from the response. The next sections provide more detail on adding content to messages.

Adding Content to the Header

To add content to the header, you create a SOAPHeaderElement object. As with all new elements, it must have an associated QName object.

For example, suppose you want to add a conformance claim header to the message to state that your message conforms to the WS-I Basic Profile. The following code fragment retrieves the SOAPHeader object from message and adds a new SOAPHeaderElement object to it. This SOAPHeaderElement object contains the correct qualified name and attribute for a WS-I conformance claim header.

SOAPHeader header = message.getSOAPHeader();
QName headerName = new QName("http://ws-i.org/schemas/conformanceClaim/",
    "Claim", "wsi");
SOAPHeaderElement headerElement =
    header.addHeaderElement(headerName);
headerElement.addAttribute(new QName("conformsTo"),
    "http://ws-i.org/profiles/basic/1.1/");

At this point, header contains the SOAPHeaderElement object headerElement identified by the QName object headerName. Note that the addHeaderElement method both creates headerElement and adds it to header.

A conformance claim header has no content. This code produces the following XML header:

<SOAP-ENV:Header>
  <wsi:Claim
    xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/"
    conformsTo="http://ws-i.org/profiles/basic/1.1/"/>
</SOAP-ENV:Header>

For more information about creating SOAP messages that conform to WS-I, see the Conformance Claim Attachment Mechanisms document described in the Conformance section of the WS-I Basic Profile.

For a different kind of header, you might want to add content to headerElement. The following line of code uses the method addTextNode to do this.

headerElement.addTextNode("order");

Now you have the SOAPHeader object header that contains a SOAPHeaderElement object whose content is "order".

Adding Content to the SOAPPart Object

If the content you want to send is in a file, SAAJ provides an easy way to add it directly to the SOAPPart object. This means that you do not access the SOAPBody object and build the XML content yourself, as you did in the preceding section.

To add a file directly to the SOAPPart object, you use a javax.xml.transform.Source object from JAXP (the Java API for XML Processing). There are three types of Source objects: SAXSource, DOMSource, and StreamSource. A StreamSource object holds an XML document in text form. SAXSource and DOMSource objects hold content along with the instructions for transforming the content into an XML document.

The following code fragment uses the JAXP API to build a DOMSource object that is passed to the SOAPPart.setContent method. The first three lines of code get a DocumentBuilderFactory object and use it to create the DocumentBuilder object builder. Because SOAP messages use namespaces, you should set the NamespaceAware property for the factory to true. Then builder parses the content file to produce a Document object.

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder builder = dbFactory.newDocumentBuilder();
Document document = builder.parse("file:///music/order/soap.xml");
DOMSource domSource = new DOMSource(document);

The following two lines of code access the SOAPPart object (using the SOAPMessage object message) and set the new Document object as its content. The SOAPPart.setContent method not only sets content for the SOAPBody object but also sets the appropriate header for the SOAPHeader object.

SOAPPart soapPart = message.getSOAPPart();
soapPart.setContent(domSource);

The XML file you use to set the content of the SOAPPart object must include Envelope and Body elements:

<SOAP-ENV:Envelope
 xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
  ...
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

You will see other ways to add content to a message in the sections Adding a Document to the SOAP Body and Adding Attachments.

Adding a Document to the SOAP Body

In addition to setting the content of the entire SOAP message to that of a DOMSource object, you can add a DOM document directly to the body of the message. This capability means that you do not have to create a javax.xml.transform.Source object. After you parse the document, you can add it directly to the message body:

SOAPBody body = message.getSOAPBody();
SOAPBodyElement docElement = body.addDocument(document);

Manipulating Message Content Using SAAJ or DOM APIs

Because SAAJ nodes and elements implement the DOM Node and Element interfaces, you have many options for adding or changing message content:

The first three of these cause no problems. After you have created a message, whether or not you have imported its content from another document, you can start adding or changing nodes using either SAAJ or DOM APIs.

But if you use DOM APIs and then switch to using SAAJ APIs to manipulate the document, any references to objects within the tree that were obtained using DOM APIs are no longer valid. If you must use SAAJ APIs after using DOM APIs, you should set all your DOM typed references to null, because they can become invalid. For more information about the exact cases in which references become invalid, see the SAAJ API documentation.

The basic rule is that you can continue manipulating the message content using SAAJ APIs as long as you want to, but after you start manipulating it using DOM, you should no longer use SAAJ APIs.

Adding Attachments

An AttachmentPart object can contain any type of content, including XML. And because the SOAP part can contain only XML content, you must use an AttachmentPart object for any content that is not in XML format.

Creating an AttachmentPart Object and Adding Content

The SOAPMessage object creates an AttachmentPart object, and the message also must add the attachment to itself after content has been added. The SOAPMessage class has three methods for creating an AttachmentPart object.

The first method creates an attachment with no content. In this case, an AttachmentPart method is used later to add content to the attachment.

AttachmentPart attachment = message.createAttachmentPart();

You add content to attachment by using the AttachmentPart method setContent. This method takes two parameters: a Java Object for the content, and a String object for the MIME content type that is used to encode the object. Content in the SOAPBody part of a message automatically has a Content-Type header with the value "text/xml" because the content must be in XML. In contrast, the type of content in an AttachmentPart object must be specified because it can be any type.

Each AttachmentPart object has one or more MIME headers associated with it. When you specify a type to the setContent method, that type is used for the header Content-Type. Note that Content-Type is the only header that is required. You may set other optional headers, such as Content-Id and Content-Location. For convenience, SAAJ provides get and set methods for the headers Content-Type, Content-Id, and Content-Location. These headers can be helpful in accessing a particular attachment when a message has multiple attachments. For example, to access the attachments that have particular headers, you can call the SOAPMessage method getAttachments and pass it a MIMEHeaders object containing the MIME headers you are interested in.

The following code fragment shows one of the ways to use the method setContent. The Java Object in the first parameter can be a String, a stream, a javax.xml.transform.Source object, or a javax.activation.DataHandler object. The Java Object being added in the following code fragment is a String, which is plain text, so the second argument must be "text/plain". The code also sets a content identifier, which can be used to identify this AttachmentPart object. After you have added content to attachment, you must add it to the SOAPMessage object, something that is done in the last line.

String stringContent = "Update address for Sunny Skies " +
    "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";

attachment.setContent(stringContent, "text/plain");
attachment.setContentId("update_address");

message.addAttachmentPart(attachment);

The attachment variable now represents an AttachmentPart object that contains the string stringContent and has a header that contains the string text/plain. It also has a Content-Id header with update_address as its value. And attachment is now part of message.

The other two SOAPMessage.createAttachment methods create an AttachmentPart object complete with content. One is very similar to the AttachmentPart.setContent method in that it takes the same parameters and does essentially the same thing. It takes a Java Object containing the content and a String giving the content type. As with AttachmentPart.setContent, the Object can be a String, a stream, a javax.xml.transform.Source object, or a javax.activation.DataHandler object.

The other method for creating an AttachmentPart object with content takes a DataHandler object, which is part of the JavaBeans Activation Framework (JAF). Using a DataHandler object is fairly straightforward. First, you create a java.net.URL object for the file you want to add as content. Then you create a DataHandler object initialized with the URL object:

URL url = new URL("http://greatproducts.com/gizmos/img.jpg");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart attachment = message.createAttachmentPart(dataHandler);
attachment.setContentId("attached_image");

message.addAttachmentPart(attachment);

You might note two things about this code fragment. First, it sets a header for Content-ID using the method setContentId. This method takes a String that can be whatever you like to identify the attachment. Second, unlike the other methods for setting content, this one does not take a String for Content-Type. This method takes care of setting the Content-Type header for you, something that is possible because one of the things a DataHandler object does is to determine the data type of the file it contains.

Accessing an AttachmentPart Object

If you receive a message with attachments or want to change an attachment to a message you are building, you need to access the attachment. The SOAPMessage class provides two versions of the getAttachments method for retrieving its AttachmentPart objects. When it is given no argument, the method SOAPMessage.getAttachments returns a java.util.Iterator object over all the AttachmentPart objects in a message. When getAttachments is given a MimeHeaders object, which is a list of MIME headers, getAttachments returns an iterator over the AttachmentPart objects that have a header that matches one of the headers in the list. The following code uses the getAttachments method that takes no arguments and thus retrieves all the AttachmentPart objects in the SOAPMessage object message. Then it prints the content ID, the content type, and the content of each AttachmentPart object.

java.util.Iterator iterator = message.getAttachments();
while (iterator.hasNext()) {
    AttachmentPart attachment = (AttachmentPart)iterator.next();
    String id = attachment.getContentId();
    String type = attachment.getContentType();
    System.out.print("Attachment " + id + " has content type " + type);
    if (type.equals("text/plain")) {
        Object content = attachment.getContent();
        System.out.println("Attachment contains:\n" + content);
    }
}

Adding Attributes

An XML element can have one or more attributes that give information about that element. An attribute consists of a name for the attribute followed immediately by an equal sign (=) and its value.

The SOAPElement interface provides methods for adding an attribute, for getting the value of an attribute, and for removing an attribute. For example, in the following code fragment, the attribute named id is added to the SOAPElement object person. Because person is a SOAPElement object rather than a SOAPBodyElement object or SOAPHeaderElement object, it is legal for its QName object to contain only a local name.

QName attributeName = new QName("id");
person.addAttribute(attributeName, "Person7");

These lines of code will generate the first line in the following XML fragment.

<person id="Person7">
  ...
</person>

The following line of code retrieves the value of the attribute whose name is id.

String attributeValue = person.getAttributeValue(attributeName);

If you had added two or more attributes to person, the preceding line of code would have returned only the value for the attribute named id. If you wanted to retrieve the values for all the attributes for person, you would use the method getAllAttributes, which returns an iterator over all the values. The following lines of code retrieve and print each value on a separate line until there are no more attribute values. Note that the Iterator.next method returns a Java Object, which is cast to a QName object so that it can be assigned to the QName object attributeName. (The examples in DOM and DOMSource Examples use code similar to this.)

Iterator iterator = person.getAllAttributesAsQNames();
while (iterator.hasNext()){
    QName attributeName = (QName) iterator.next();
    System.out.println("Attribute name is " + attributeName.toString());
    System.out.println("Attribute value is " + 
        element.getAttributeValue(attributeName));
}

The following line of code removes the attribute named id from person. The variable successful will be true if the attribute was removed successfully.

boolean successful = person.removeAttribute(attributeName);

In this section you have seen how to add, retrieve, and remove attributes. This information is general in that it applies to any element. The next section discusses attributes that can be added only to header elements.

Header Attributes

Attributes that appear in a SOAPHeaderElement object determine how a recipient processes a message. You can think of header attributes as offering a way to extend a message, giving information about such things as authentication, transaction management, payment, and so on. A header attribute refines the meaning of the header, whereas the header refines the meaning of the message contained in the SOAP body.

The SOAP 1.1 specification defines two attributes that can appear only in SOAPHeaderElement objects: actor and mustUnderstand.

The SOAP 1.2 specification defines three such attributes: role (a new name for actor), mustUnderstand, and relay.

The next sections discuss these attributes.

See Header Example for an example that uses the code shown in this section.

The actor Attribute

The actor attribute is optional, but if it is used, it must appear in a SOAPHeaderElement object. Its purpose is to indicate the recipient of a header element. The default actor is the message’s ultimate recipient; that is, if no actor attribute is supplied, the message goes directly to the ultimate recipient.

An actor is an application that can both receive SOAP messages and forward them to the next actor. The ability to specify one or more actors as intermediate recipients makes it possible to route a message to multiple recipients and to supply header information that applies specifically to each of the recipients.

For example, suppose that a message is an incoming purchase order. Its SOAPHeader object might have SOAPHeaderElement objects with actor attributes that route the message to applications that function as the order desk, the shipping desk, the confirmation desk, and the billing department. Each of these applications will take the appropriate action, remove the SOAPHeaderElement objects relevant to it, and send the message on to the next actor.


Note –

Although the SAAJ API provides the API for adding these attributes, it does not supply the API for processing them. For example, the actor attribute requires that there be an implementation such as a messaging provider service to route the message from one actor to the next.


An actor is identified by its URI. For example, the following line of code, in which orderHeader is a SOAPHeaderElement object, sets the actor to the given URI.

orderHeader.setActor("http://gizmos.com/orders");

Additional actors can be set in their own SOAPHeaderElement objects. The following code fragment first uses the SOAPMessage object message to get its SOAPHeader object header. Then header creates four SOAPHeaderElement objects, each of which sets its actor attribute.

SOAPHeader header = message.getSOAPHeader();
SOAPFactory soapFactory = SOAPFactory.newInstance();

String nameSpace = "ns";
String nameSpaceURI = "http://gizmos.com/NSURI";

QName order = new QName(nameSpaceURI, "orderDesk", nameSpace);
SOAPHeaderElement orderHeader = header.addHeaderElement(order);
orderHeader.setActor("http://gizmos.com/orders");

QName shipping = new QName(nameSpaceURI, "shippingDesk", nameSpace);
SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping);
shippingHeader.setActor("http://gizmos.com/shipping");

QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);
SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);
confirmationHeader.setActor("http://gizmos.com/confirmations");

QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);
SOAPHeaderElement billingHeader = header.addHeaderElement(billing);
billingHeader.setActor("http://gizmos.com/billing");

The SOAPHeader interface provides two methods that return a java.util.Iterator object over all the SOAPHeaderElement objects that have an actor that matches the specified actor. The first method, examineHeaderElements, returns an iterator over all the elements that have the specified actor.

java.util.Iterator headerElements =
    header.examineHeaderElements("http://gizmos.com/orders");

The second method, extractHeaderElements, not only returns an iterator over all the SOAPHeaderElement objects that have the specified actor attribute but also detaches them from the SOAPHeader object. So, for example, after the order desk application did its work, it would call extractHeaderElements to remove all the SOAPHeaderElement objects that applied to it.

java.util.Iterator headerElements =
    header.extractHeaderElements("http://gizmos.com/orders");

Each SOAPHeaderElement object can have only one actor attribute, but the same actor can be an attribute for multiple SOAPHeaderElement objects.

Two additional SOAPHeader methods, examineAllHeaderElements and extractAllHeaderElements, allow you to examine or extract all the header elements, whether or not they have an actor attribute. For example, you could use the following code to display the values of all the header elements:

Iterator allHeaders = header.examineAllHeaderElements();
while (allHeaders.hasNext()) {
    SOAPHeaderElement headerElement = (SOAPHeaderElement)allHeaders.next();
    QName headerName = headerElement.getElementQName();
    System.out.println("\nHeader name is " + headerName.toString());
    System.out.println("Actor is " + headerElement.getActor());
}

The role Attribute

The role attribute is the name used by the SOAP 1.2 specification for the SOAP 1.2 actor attribute. The SOAPHeaderElement methods setRole and getRole perform the same functions as the setActor and getActor methods.

The mustUnderstand Attribute

The other attribute that must be added only to a SOAPHeaderElement object is mustUnderstand. This attribute says whether or not the recipient (indicated by the actor attribute) is required to process a header entry. When the value of the mustUnderstand attribute is true, the actor must understand the semantics of the header entry and must process it correctly to those semantics. If the value is false, processing the header entry is optional. A SOAPHeaderElement object with no mustUnderstand attribute is equivalent to one with a mustUnderstand attribute whose value is false.

The mustUnderstand attribute is used to call attention to the fact that the semantics in an element are different from the semantics in its parent or peer elements. This allows for robust evolution, ensuring that a change in semantics will not be silently ignored by those who may not fully understand it.

If the actor for a header that has a mustUnderstand attribute set to true cannot process the header, it must send a SOAP fault back to the sender. (See Using SOAP Faults.) The actor must not change state or cause any side effects, so that, to an outside observer, it appears that the fault was sent before any header processing was done.

For example, you could set the mustUnderstand attribute to true for the confirmationHeader in the code fragment in The actor Attribute:

QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);
SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);
confirmationHeader.setActor("http://gizmos.com/confirmations");
confirmationHeader.setMustUnderstand(true);

This fragment produces the following XML:

<ns:confirmationDesk
  xmlns:ns="http://gizmos.com/NSURI"
  SOAP-ENV:actor="http://gizmos.com/confirmations"
  SOAP-ENV:mustUnderstand="1"/>

You can use the getMustUnderstand method to retrieve the value of the mustUnderstand attribute. For example, you could add the following to the code fragment at the end of the preceding section:

System.out.println("mustUnderstand is " + headerElement.getMustUnderstand());

The relay Attribute

The SOAP 1.2 specification adds a third attribute to a SOAPHeaderElement, relay. This attribute, like mustUnderstand, is a boolean value. If it is set to true, it indicates that the SOAP header block must not be processed by any node that is targeted by the header block, but must only be passed on to the next targeted node. This attribute is ignored on header blocks whose mustUnderstand attribute is set to true or that are targeted at the ultimate receiver (which is the default). The default value of this attribute is false.

For example, you could set the relay element to true for the billingHeader in the code fragment in The actor Attribute (also changing setActor to setRole):

QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);
SOAPHeaderElement billingHeader = header.addHeaderElement(billing);
billingHeader.setRole("http://gizmos.com/billing");
billingHeader.setRelay(true);

This fragment produces the following XML:

<ns:billingDesk
  xmlns:ns="http://gizmos.com/NSURI"
  env:relay="true"
  env:role="http://gizmos.com/billing"/>

To display the value of the attribute, call getRelay:

System.out.println("relay is " + headerElement.getRelay());

Using SOAP Faults

In this section, you will see how to use the API for creating and accessing a SOAP fault element in an XML message.

Overview of SOAP Faults

If you send a message that was not successful for some reason, you may get back a response containing a SOAP fault element, which gives you status information, error information, or both. There can be only one SOAP fault element in a message, and it must be an entry in the SOAP body. Furthermore, if there is a SOAP fault element in the SOAP body, there can be no other elements in the SOAP body. This means that when you add a SOAP fault element, you have effectively completed the construction of the SOAP body.

A SOAPFault object, the representation of a SOAP fault element in the SAAJ API, is similar to an Exception object in that it conveys information about a problem. However, a SOAPFault object is quite different in that it is an element in a message’s SOAPBody object rather than part of the try/catch mechanism used for Exception objects. Also, as part of the SOAPBody object, which provides a simple means for sending mandatory information intended for the ultimate recipient, a SOAPFault object only reports status or error information. It does not halt the execution of an application, as an Exception object can.

If you are a client using the SAAJ API and are sending point-to-point messages, the recipient of your message may add a SOAPFault object to the response to alert you to a problem. For example, if you sent an order with an incomplete address for where to send the order, the service receiving the order might put a SOAPFault object in the return message telling you that part of the address was missing.

Another example of who might send a SOAP fault is an intermediate recipient, or actor. As stated in the section Adding Attributes, an actor that cannot process a header that has a mustUnderstand attribute with a value of true must return a SOAP fault to the sender.

A SOAPFault object contains the following elements:

Creating and Populating a SOAPFault Object

You have seen how to add content to a SOAPBody object; this section walks you through adding a SOAPFault object to a SOAPBody object and then adding its constituent parts.

As with adding content, the first step is to access the SOAPBody object.

SOAPBody body = message.getSOAPBody();

With the SOAPBody object body in hand, you can use it to create a SOAPFault object. The following line of code creates a SOAPFault object and adds it to body.

SOAPFault fault = body.addFault();

The SOAPFault interface provides convenience methods that create an element, add the new element to the SOAPFault object, and add a text node, all in one operation. For example, in the following lines of SOAP 1.1 code, the method setFaultCode creates a faultcode element, adds it to fault, and adds a Text node with the value "SOAP-ENV:Server" by specifying a default prefix and the namespace URI for a SOAP envelope.

QName faultName = new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE, "Server");
fault.setFaultCode(faultName);
fault.setFaultActor("http://gizmos.com/orders");
fault.setFaultString("Server not responding");

The SOAP 1.2 code would look like this:

QName faultName = new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "Receiver");
fault.setFaultCode(faultName);
fault.setFaultRole("http://gizmos.com/order");
fault.addFaultReasonText("Server not responding", Locale.US);

To add one or more subcodes to the fault code, call the method fault.appendFaultSubcode, which takes a QName argument.

The SOAPFault object fault, created in the preceding lines of code, indicates that the cause of the problem is an unavailable server and that the actor at http://gizmos.com/orders is having the problem. If the message were being routed only to its ultimate destination, there would have been no need to set a fault actor. Also note that fault does not have a Detail object because it does not relate to the SOAPBody object. (If you use SOAP 1.2, you can use the setFaultRole method instead of setFaultActor.)

The following SOAP 1.1 code fragment creates a SOAPFault object that includes a Detail object. Note that a SOAPFault object can have only one Detail object, which is simply a container for DetailEntry objects, but the Detail object can have multiple DetailEntry objects. The Detail object in the following lines of code has two DetailEntry objects added to it.

SOAPFault fault = body.addFault();

QName faultName = new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE, "Client");
fault.setFaultCode(faultName);
fault.setFaultString("Message does not have necessary info");

Detail detail = fault.addDetail();

QName entryName = new QName("http://gizmos.com/orders/", "order", "PO");
DetailEntry entry = detail.addDetailEntry(entryName);
entry.addTextNode("Quantity element does not have a value");

QName entryName2 = new QName("http://gizmos.com/orders/", "order", "PO");
DetailEntry entry2 = detail.addDetailEntry(entryName2);
entry2.addTextNode("Incomplete address: no zip code");

See SOAP Fault Example for an example that uses code like that shown in this section.

The SOAP 1.1 and 1.2 specifications define slightly different values for a fault code. Table 19–1 lists and describes these values.

Table 19–1 SOAP Fault Code Values

SOAP 1.1 

SOAP 1.2 

Description 

VersionMismatch 

VersionMismatch 

The namespace or local name for a SOAPEnvelope object was invalid.

MustUnderstand 

MustUnderstand 

An immediate child element of a SOAPHeader object had its mustUnderstand attribute set to true, and the processing party did not understand the element or did not obey it.

Client 

Sender 

The SOAPMessage object was not formed correctly or did not contain the information needed to succeed.

Server 

Receiver 

The SOAPMessage object could not be processed because of a processing error, not because of a problem with the message itself.

N/A 

DataEncodingUnknown 

A SOAP header block or SOAP body child element information item targeted at the faulting SOAP node is scoped with a data encoding that the faulting node does not support. 

Retrieving Fault Information

Just as the SOAPFault interface provides convenience methods for adding information, it also provides convenience methods for retrieving that information. The following code fragment shows what you might write to retrieve fault information from a message you received. In the code fragment, newMessage is the SOAPMessage object that has been sent to you. Because a SOAPFault object must be part of the SOAPBody object, the first step is to access the SOAPBody object. Then the code tests to see whether the SOAPBody object contains a SOAPFault object. If it does, the code retrieves the SOAPFault object and uses it to retrieve its contents. The convenience methods getFaultCode, getFaultString, and getFaultActor make retrieving the values very easy.

SOAPBody body = newMessage.getSOAPBody();
if ( body.hasFault() ) {
    SOAPFault newFault = body.getFault();
    QName code = newFault.getFaultCodeAsQName();
    String string = newFault.getFaultString();
    String actor = newFault.getFaultActor();

To retrieve subcodes from a SOAP 1.2 fault, call the method newFault.getFaultSubcodes.

Next the code prints the values it has just retrieved. Not all messages are required to have a fault actor, so the code tests to see whether there is one. Testing whether the variable actor is null works because the method getFaultActor returns null if a fault actor has not been set.

    System.out.println("SOAP fault contains: ");
    System.out.println("  Fault code = " + code.toString());
    System.out.println("  Local name = " + code.getLocalPart());
    System.out.println("  Namespace prefix = " +
        code.getPrefix() + ", bound to " + code.getNamespaceURI());
    System.out.println("  Fault string = " + string);

    if ( actor != null ) {
        System.out.println("  Fault actor = " + actor);
    }

The final task is to retrieve the Detail object and get its DetailEntry objects. The code uses the SOAPFault object newFault to retrieve the Detail object newDetail, and then it uses newDetail to call the method getDetailEntries. This method returns the java.util.Iterator object entries, which contains all the DetailEntry objects in newDetail. Not all SOAPFault objects are required to have a Detail object, so the code tests to see whether newDetail is null. If it is not, the code prints the values of the DetailEntry objects as long as there are any.

Detail newDetail = newFault.getDetail();
if (newDetail != null) {
    Iterator entries = newDetail.getDetailEntries();
    while ( entries.hasNext() ) {
        DetailEntry newEntry = (DetailEntry)entries.next();
        String value = newEntry.getValue();
        System.out.println("  Detail entry = " + value);
    }
}

In summary, you have seen how to add a SOAPFault object and its contents to a message as well as how to retrieve the contents. A SOAPFault object, which is optional, is added to the SOAPBody object to convey status or error information. It must always have a fault code and a String explanation of the fault. A SOAPFault object must indicate the actor that is the source of the fault only when there are multiple actors; otherwise, it is optional. Similarly, the SOAPFault object must contain a Detail object with one or more DetailEntry objects only when the contents of the SOAPBody object could not be processed successfully.

See SOAP Fault Example for an example that uses code like that shown in this section.

Code Examples

The first part of this tutorial uses code fragments to walk you through the fundamentals of using the SAAJ API. In this section, you will use some of those code fragments to create applications. First, you will see the program Request.java. Then you will see how to run the programs HeaderExample.java, DOMExample.java, DOMSrcExample.java, Attachments.java, and SOAPFaultTest.java.


Note –

Before you run any of the examples, follow the preliminary setup instructions in Building the Examples.


Request Example

The class Request puts together the code fragments used in the section SAAJ Tutorial and adds what is needed to make it a complete example of a client sending a request-response message. In addition to putting all the code together, it adds import statements, a main method, and a try/catch block with exception handling.

import javax.xml.soap.*;
import javax.xml.namespace.QName;
import java.util.Iterator;
import java.net.URL;

public class Request {
    public static void main(String[] args)    {
        try {
            SOAPConnectionFactory soapConnectionFactory =
                SOAPConnectionFactory.newInstance();
            SOAPConnection connection =
                soapConnectionFactory.createConnection();

            MessageFactory factory = MessageFactory.newInstance();
            SOAPMessage message = factory.createMessage();

            SOAPHeader header = message.getSOAPHeader();
            SOAPBody body = message.getSOAPBody();
            header.detachNode();

            QName bodyName = new QName("http://wombat.ztrade.com",
                "GetLastTradePrice", "m");
            SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

            QName name = new QName("symbol");
            SOAPElement symbol = bodyElement.addChildElement(name);
            symbol.addTextNode("SUNW");

            URL endpoint = new URL("http://wombat.ztrade.com/quotes");
            SOAPMessage response = connection.call(message, endpoint);

            connection.close();

            SOAPBody soapBody = response.getSOAPBody();

            Iterator iterator = soapBody.getChildElements(bodyName);
            bodyElement = (SOAPBodyElement)iterator.next();
            String lastPrice = bodyElement.getValue();

            System.out.print("The last price for SUNW is ");
            System.out.println(lastPrice);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

For the Request class to be runnable, the second argument supplied to the call method would have to be a valid existing URI, and this is not true in this case.

Header Example

The example HeaderExample.java, based on the code fragments in the section Adding Attributes, creates a message that has several headers. It then retrieves the contents of the headers and prints them. The example generates either a SOAP 1.1 message or a SOAP 1.2 message, depending on arguments you specify. You will find the code for HeaderExample in the following directory:

tut-install/javaeetutorial5/examples/saaj/headers/src/

Building and Running the Header Example

    To build the program using NetBeans IDE, follow these steps:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/saaj/.

  3. Select the headers folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

    A Reference Problems dialog appears. Click Close.

  6. Right-click the headers project and choose Resolve Reference Problems.

  7. In the Resolve Reference Problems dialog, select the first of the missing JAR files and click Resolve.

    The missing files are activation.jar, javaee.jar, and appserv-ws.jar.

  8. Navigate to the as-install/lib/ directory.

  9. Select the missing JAR file (activation.jar, for example) and click Open.

    In the Resolve Reference Problems dialog, all the files have green check marks to the left of their names.

  10. Click Close.

  11. Right-click the project and choose Build.

    To run the program using NetBeans IDE, follow these steps:

  1. Right-click the headers project and choose Properties.

  2. Select Run from the Categories tree.

  3. In the Arguments field, type the following:


    1.1
    

    This argument specifies the version of SOAP to be used in generating the message.

  4. Click OK.

  5. Right-click the project and choose Run.

  6. Right-click the project and choose Properties.

  7. Select Run from the Categories tree.

  8. In the Arguments field, type the following:


    1.2
    
  9. Click OK.

  10. Right-click the project and choose Run.

To build and run HeaderExample using Ant, go to the directory tut-install/javaeetutorial5/examples/saaj/headers/. Use one of the following commands:


ant run-headers -Dsoap=1.1

ant run-headers -Dsoap=1.2

When you run HeaderExample to generate a SOAP 1.1 message, you will see output similar to the following:


----- Request Message ----

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<ns:orderDesk xmlns:ns="http://gizmos.com/NSURI"
 SOAP-ENV:actor="http://gizmos.com/orders"/>
<ns:shippingDesk xmlns:ns="http://gizmos.com/NSURI"
 SOAP-ENV:actor="http://gizmos.com/shipping"/>
<ns:confirmationDesk xmlns:ns="http://gizmos.com/NSURI"
 SOAP-ENV:actor="http://gizmos.com/confirmations" SOAP-ENV:mustUnderstand="1"/>
<ns:billingDesk xmlns:ns="http://gizmos.com/NSURI"
 SOAP-ENV:actor="http://gizmos.com/billing"/>
</SOAP-ENV:Header><SOAP-ENV:Body/></SOAP-ENV:Envelope>

Header name is {http://gizmos.com/NSURI}orderDesk
Actor is http://gizmos.com/orders
mustUnderstand is false

Header name is {http://gizmos.com/NSURI}shippingDesk
Actor is http://gizmos.com/shipping
mustUnderstand is false

Header name is {http://gizmos.com/NSURI}confirmationDesk
Actor is http://gizmos.com/confirmations
mustUnderstand is true

Header name is {http://gizmos.com/NSURI}billingDesk
Actor is http://gizmos.com/billing
mustUnderstand is false

When you run HeaderExample to generate a SOAP 1.2 message, you will see output similar to the following:


----- Request Message ----

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<ns:orderDesk xmlns:ns="http://gizmos.com/NSURI" 
 env:role="http://gizmos.com/orders"/>
<ns:shippingDesk xmlns:ns="http://gizmos.com/NSURI"
 env:role="http://gizmos.com/shipping"/>
<ns:confirmationDesk xmlns:ns="http://gizmos.com/NSURI"
 env:mustUnderstand="true" env:role="http://gizmos.com/confirmations"/>
<ns:billingDesk xmlns:ns="http://gizmos.com/NSURI"
 env:relay="true" env:role="http://gizmos.com/billing"/>
</env:Header><env:Body/></env:Envelope>

Header name is {http://gizmos.com/NSURI}orderDesk
Role is http://gizmos.com/orders
mustUnderstand is false
relay is false

Header name is {http://gizmos.com/NSURI}shippingDesk
Role is http://gizmos.com/shipping
mustUnderstand is false
relay is false

Header name is {http://gizmos.com/NSURI}confirmationDesk
Role is http://gizmos.com/confirmations
mustUnderstand is true
relay is false

Header name is {http://gizmos.com/NSURI}billingDesk
Role is http://gizmos.com/billing
mustUnderstand is false
relay is true

DOM and DOMSource Examples

The examples DOMExample.java and DOMSrcExample.java show how to add a DOM document to a message and then traverse its contents. They show two ways to do this:

You will find the code for DOMExample and DOMSrcExample in the following directory:

tut-install/javaeetutorial5/examples/saaj/dom/src/

Examining the DOMExample Class

DOMExample first creates a DOM document by parsing an XML document. The file it parses is one that you specify on the command line.

static Document document;
...
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    try {
        DocumentBuilder builder = factory.newDocumentBuilder();
        document = builder.parse( new File(args[0]) );
        ...

Next, the example creates a SOAP message in the usual way. Then it adds the document to the message body:

        SOAPBodyElement docElement = body.addDocument(document);

This example does not change the content of the message. Instead, it displays the message content and then uses a recursive method, getContents, to traverse the element tree using SAAJ APIs and display the message contents in a readable form.

public void getContents(Iterator iterator, String indent) {

    while (iterator.hasNext()) {
        Node node = (Node) iterator.next();
        SOAPElement element = null;
        Text text = null;
        if (node instanceof SOAPElement) {
            element = (SOAPElement)node;
            QName name = element.getElementQName();
            System.out.println(indent + "Name is " + name.toString());
            Iterator attrs = element.getAllAttributesAsQNames();
            while (attrs.hasNext()){
                QName attrName = (QName)attrs.next();
                System.out.println(indent + " Attribute name is " +
                     attrName.toString());
                System.out.println(indent + " Attribute value is " +
                     element.getAttributeValue(attrName));
            }
            Iterator iter2 = element.getChildElements();
            getContents(iter2, indent + " ");
        } else {
            text = (Text) node;
            String content = text.getValue();
            System.out.println(indent + "Content is: " + content);
            }
        }
    }

Examining the DOMSrcExample Class

DOMSrcExample differs from DOMExample in only a few ways. First, after it parses the document, DOMSrcExample uses the document to create a DOMSource object. This code is the same as that of DOMExample except for the last line:

    static DOMSource domSource;
    ...
    try {
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(new File(args[0]));
        domSource = new DOMSource(document);
        ...

Then, after DOMSrcExample creates the message, it does not get the header and body and add the document to the body, as DOMExample does. Instead, DOMSrcExample gets the SOAP part and sets the DOMSource object as its content:

// Create a message
SOAPMessage message = messageFactory.createMessage();

// Get the SOAP part and set its content to domSource
SOAPPart soapPart = message.getSOAPPart();
soapPart.setContent(domSource);

The example then uses the getContents method to obtain the contents of both the header (if it exists) and the body of the message.

The most important difference between these two examples is the kind of document you can use to create the message. Because DOMExample adds the document to the body of the SOAP message, you can use any valid XML file to create the document. But because DOMSrcExample makes the document the entire content of the message, the document must already be in the form of a valid SOAP message, and not just any XML document.

Building and Running the DOM and DOMSource Examples

When you run DOMExample and DOMSrcExample, you can specify one of two sample XML files in the directory tut-install/javaeetutorial5/examples/saaj/dom/:

You can use either of these files when you run DOMExample. You can use domsrc.xml to run DOMSrcExample.

    To build the programs using NetBeans IDE, follow these steps:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/saaj/.

  3. Select the dom folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

    A Reference Problems dialog appears. Click Close.

  6. Right-click the dom project and choose Resolve Reference Problems.

  7. In the Resolve Reference Problems dialog, select the first of the missing JAR files and click Resolve.

    The missing files are activation.jar, javaee.jar, and appserv-ws.jar.

  8. Navigate to the as-install/lib/ directory.

  9. Select the missing JAR file (activation.jar, for example) and click Open.

    In the Resolve Reference Problems dialog, all the files have green check marks to the left of their names.

  10. Click Close.

  11. Right-click the project and choose Build.

    To run DOMExample using NetBeans IDE, follow these steps:

  1. Right-click the dom project and choose Properties.

  2. Select Run from the Categories tree.

  3. Click Browse next to the Main Class field.

  4. In the Browse Main Classes dialog, select DomExample.

  5. Click Select Main Class.

  6. In the Arguments field, type the following:


    slide.xml
    
  7. Click OK.

  8. Right-click the project and choose Run.

    To run DOMSrcExample using NetBeans IDE, follow these steps:

  1. Right-click the dom project and choose Properties.

  2. Select Run from the Categories tree.

  3. Click Browse next to the Main Class field.

  4. In the Browse Main Classes dialog, select DomSrcExample.

  5. Click Select Main Class.

  6. In the Arguments field, type the following:


    domsrc.xml
    
  7. Click OK.

  8. Right-click the project and choose Run.

To run the examples using Ant, go to the directory tut-install/javaeetutorial5/examples/saaj/dom/.

To run DOMExample using Ant, use the following command:


ant run-dom -Dxml-file=slide.xml

To run DOMSrcExample using Ant, use the following command:


ant run-domsrc -Dxml-file=domsrc.xml

When you run DOMExample using the file slide.xml, you will see output that begins like the following:


     Running DOMExample.
     Name is slideshow
      Attribute name is author
      Attribute value is Yours Truly
      Attribute name is date
      Attribute value is Date of publication
      Attribute name is title
      Attribute value is Sample Slide Show
      Content is: 
...

When you run DOMSrcExample using the file domsrc.xml, you will see output that begins like the following:


     Running DOMSrcExample.
     Header contents:
     Content is: 

     Name is {http://gizmos.com/NSURI}orderDesk
      Attribute name is SOAP-ENV:actor
      Attribute value is http://gizmos.com/orders
     Content is: 
    ...

If you run DOMSrcExample with the file slide.xml, you will see runtime errors.

Attachments Example

The example Attachments.java, based on the code fragments in the sections Creating an AttachmentPart Object and Adding Content and Accessing an AttachmentPart Object, creates a message that has a text attachment and an image attachment. It then retrieves the contents of the attachments and prints the contents of the text attachment. You will find the code for the Attachments class in the following directory:

tut-install/javaeetutorial5/examples/saaj/attachments/src/

Attachments first creates a message in the usual way. It then creates an AttachmentPart for the text attachment:

AttachmentPart attachment1 = message.createAttachmentPart();

After it reads input from a file into a string named stringContent, it sets the content of the attachment to the value of the string and the type to text/plain and also sets a content ID.

attachment1.setContent(stringContent, "text/plain");
attachment1.setContentId("attached_text");

It then adds the attachment to the message:

message.addAttachmentPart(attachment1);

The example uses a javax.activation.DataHandler object to hold a reference to the graphic that constitutes the second attachment. It creates this attachment using the form of the createAttachmentPart method that takes a DataHandler argument.

// Create attachment part for image
URL url = new URL("file:///../xml-pic.jpg");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart attachment2 = message.createAttachmentPart(dataHandler);
attachment2.setContentId("attached_image");

message.addAttachmentPart(attachment2);

The example then retrieves the attachments from the message. It displays the contentId and contentType attributes of each attachment and the contents of the text attachment.

Building and Running the Attachments Example

The Attachments class takes a text file as an argument. You can specify any text file. The attachments directory contains a file named addr.txt that you can use.

    To build the program using NetBeans IDE, follow these steps:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/saaj/.

  3. Select the attachments folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

    A Reference Problems dialog appears. Click Close.

  6. Right-click the attachments project and choose Resolve Reference Problems.

  7. In the Resolve Reference Problems dialog, select the first of the missing JAR files and click Resolve.

    The missing files are activation.jar, javaee.jar, and appserv-ws.jar.

  8. Navigate to the as-install/lib/ directory.

  9. Select the missing JAR file (activation.jar, for example) and click Open.

    In the Resolve Reference Problems dialog, all the files have green check marks to the left of their names.

  10. Click Close.

  11. Right-click the project and choose Build.

    To run the program using NetBeans IDE, follow these steps:

  1. Right-click the attachments project and choose Properties.

  2. Select Run from the Categories tree.

  3. In the Arguments field, type the name of a text file:


    addr.txt
    
  4. Click OK.

  5. Right-click the project and choose Run.

To run Attachments using Ant, go to the directory tut-install/javaeetutorial5/examples/saaj/attachments/. Use the following command:


ant run-att -Dfile=path-name

Specify a text file as the path-name argument:


ant run-att -Dfile=addr.txt

When you run Attachments using this file, you will see output like the following:


Running Attachments.
Attachment attached_text has content type text/plain
Attachment contains:
Update address for Sunny Skies, Inc., to
10 Upbeat Street
Pleasant Grove, CA 95439
USA

Attachment attached_image has content type image/jpeg

SOAP Fault Example

The example SOAPFaultTest.java, based on the code fragments in the sections Creating and Populating a SOAPFault Object and Retrieving Fault Information, creates a message that has a SOAPFault object. It then retrieves the contents of the SOAPFault object and prints them. You will find the code for SOAPFaultTest in the following directory:

tut-install/javaeetutorial5/examples/saaj/fault/src/

Like HeaderExample, the SOAPFaultTest class contains code that allows you to generate either a SOAP 1.1 or a SOAP 1.2 message.

Building and Running the SOAP Fault Example

    To build the program using NetBeans IDE, follow these steps:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/saaj/.

  3. Select the fault folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project.

    A Reference Problems dialog appears. Click Close.

  6. Right-click the fault project and choose Resolve Reference Problems.

  7. In the Resolve Reference Problems dialog, select the first of the missing JAR files and click Resolve.

    The missing files are activation.jar, javaee.jar, and appserv-ws.jar.

  8. Navigate to the as-install/lib/ directory.

  9. Select the missing JAR file (activation.jar, for example) and click Open.

    In the Resolve Reference Problems dialog, all the files have green check marks to the left of their names.

  10. Click Close.

  11. Right-click the project and choose Build.

    To run the program using NetBeans IDE, follow these steps:

  1. Right-click the fault project and choose Properties.

  2. Select Run from the Categories tree.

  3. In the Arguments field, type the following:


    1.1
    

    This argument specifies the version of SOAP to be used in generating the message.

  4. Click OK.

  5. Right-click the project and choose Run.

  6. Right-click the project and choose Properties.

  7. Select Run from the Categories tree.

  8. In the Arguments field, type the following:


    1.2
    
  9. Click OK.

  10. Right-click the project and choose Run.

To build and run SOAPFaultTest using Ant, go to the directory tut-install/javaeetutorial5/examples/saaj/fault/. Use one of the following commands:


ant run-fault -Dsoap=1.1

ant run-fault -Dsoap=1.2

When you run SOAPFaultTest to generate a SOAP 1.1 message, you will see output like the following (line breaks have been inserted in the message for readability):


Here is what the XML message looks like:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/><SOAP-ENV:Body>
<SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Message does not have necessary info</faultstring>
<faultactor>http://gizmos.com/order</faultactor>
<detail>
<PO:order xmlns:PO="http://gizmos.com/orders/">
Quantity element does not have a value</PO:order>
<PO:confirmation xmlns:PO="http://gizmos.com/confirm">
Incomplete address: no zip code</PO:confirmation>
</detail></SOAP-ENV:Fault>
</SOAP-ENV:Body></SOAP-ENV:Envelope>

SOAP fault contains:
 Fault code = {http://schemas.xmlsoap.org/soap/envelope/}Client
 Local name = Client
 Namespace prefix = SOAP-ENV, bound to http://schemas.xmlsoap.org/soap/envelope/
 Fault string = Message does not have necessary info
 Fault actor = http://gizmos.com/order
 Detail entry = Quantity element does not have a value
 Detail entry = Incomplete address: no zip code

When you run SOAPFaultTest to generate a SOAP 1.2 message, the output looks like this:


Here is what the XML message looks like:

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header/><env:Body>
<env:Fault>
<env:Code><env:Value>env:Sender</env:Value></env:Code>
<env:Reason><env:Text xml:lang="en-US">
Message does not have necessary info
</env:Text></env:Reason>
<env:Role>http://gizmos.com/order</env:Role>
<env:Detail>
<PO:order xmlns:PO="http://gizmos.com/orders/">
Quantity element does not have a value</PO:order>
<PO:confirmation xmlns:PO="http://gizmos.com/confirm">
Incomplete address: no zip code</PO:confirmation>
</env:Detail></env:Fault>
</env:Body></env:Envelope>

SOAP fault contains:
 Fault code = {http://www.w3.org/2003/05/soap-envelope}Sender
 Local name = Sender
 Namespace prefix = env, bound to http://www.w3.org/2003/05/soap-envelope
 Fault reason text = Message does not have necessary info
 Fault role = http://gizmos.com/order
 Detail entry = Quantity element does not have a value
 Detail entry = Incomplete address: no zip code

Further Information about SAAJ

For more information about SAAJ, SOAP, and WS-I, see: