Describe the functions and capabilities of JAXB, including the JAXB process flow, such as XML-to-Java and Java-to-XML, and the binding and validation mechanisms provided by JAXB.

JAXB defines an architecture for binding XML schemata to Java objects. These bindings allow you to unmarshal XML documents into a hierarchy of Java objects and marshal the Java objects into XML with minimal effort. If you work a lot with XML, you know how tedious it can be to write Simple API for XML (SAX) or Document Object Model (DOM) code to convert XML into Java objects that mean something to your program. JAXB generates code automatically so you can go about the business of processing data instead of parsing it.

Latest version of JAXB supports XML schema definitions and allows additional binding declarations to be defined inside of the schema using XML schema annotations.

The JAXB API, defined in the javax.xml.bind package, is a set of interfaces through which client applications communicate with code generated from a schema. The center of the JAXB API is JAXBContext, the client' s entry point. It provides an abstraction for managing the XML-Java binding information necessary to implement the JAXB binding framework operations: unmarshal, marshal and validate.

These three aspects of JAXB are covered by three separate interfaces. Instances of those interfaces can be created from a JAXBContext object:

JAXBContext is an abstract class defined in the API, so its actual implementation is vendor-dependent. To create a new instance of JAXBContext, you use the static newInstance(contextPath) method.

JAXBContext context = JAXBContext.newInstance("org.acme.foo:org.acme.bar");
					
The contextPath contains a list of Java package names that contain schema derived interfaces. The value of this parameter initializes the JAXBContext object so that it is capable of managing the schema derived interfaces. The client application must supply a context path which is a list of colon (':') separated java package names that contain schema derived classes. In this way, the unmarshaller will look at a document and figure out which package to use. This makes it easy to read in different types of documents without knowing their type in advance.

Unmarshalling (XML-to-Java)

An unmarshaller is used to read XML and build an object tree from classes generated by the compiler. To read an XML file, you would simply do:

...		
JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setValidating(true);
Item item = (Item) unmarshaller.unmarshal(new File("item.xml"));
...
					
There are other overloaded versions that take different types of input, such as InputStream or InputSource. You can even unmarshal a javax.xml.transform.Source object. All in all, it's similar to the way DOM trees are parsed.

Here are some more examples of unmarshalling:

Unmarshalling from a File:

JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal( new File( "xmlFile.xml" ) );
					

Unmarshalling from a java.io.InputStream:

InputStream is = new FileInputStream( "xmlFile.xml" );
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal( is );
					

Unmarshalling from a java.net.URL:

JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
Unmarshaller u = jc.createUnmarshaller();
URL url = new URL( "http://server.com/xmlFile.xml" );
Object o = u.unmarshal( url );
					

Unmarshalling from a StringBuffer using a javax.xml.transform.stream.StreamSource:

					
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
Unmarshaller u = jc.createUnmarshaller();
StringBuffer xmlStr = new StringBuffer( "<?xml version='1.0'?> ..." );
Object o = u.unmarshal( new StreamSource( new StringReader( xmlStr.toString() ) ) );

					

Unmarshalling from a org.w3c.dom.Node:

JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
Unmarshaller u = jc.createUnmarshaller();
 
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File( "xmlFile.xml"));

Object o = u.unmarshal( doc );
					

By default, Unmarshaller is very forgiving. Even if a document is invalid, it tries to recover from errors. If the document is so broken that it cannot be read, an javax.xml.bind.UnmarshalException (child of javax.xml.bind.JAXBException) will be thrown. It's often desirable to get more information about errors or reject documents with errors. The first step to do this is to set ValidationEventHandler to the Unmarshaller. A ValidationEventHandler can explicitly tell a JAXB implementation whether it should reject a document or try to recover from errors. It also gives you more information, such as line numbers, about errors.

An Unmarshaller can validate a document with the schema while unmarshalling. With this option turned on, it rejects anything short of a valid document. However, W3C XML Schema validation can be very costly. Another possibility is to set up a SAX pipeline in such a way that your XML parser does the validation; alternately, you could install a stand-alone validator in the pipeline. In this way, for example, you can change your schema to change what you get from the compiler, while maintaining the scrutiny of the original schema.

Marshalling (Java-to-XML)

A Marshaller is used to write an object graph into XML. To write an object o to a file, you would do:

...					
JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
Marshaller marshaller = jaxbContext.createMarshaller();
ObjectFactory itemMaker = new ObjectFactory();
Item item = itemMaker.createItem();
marshaller.marshal(item, new FileOutputStream("newIem.xml"));
...
					

There are other overloaded versions which allow you to produce XML as a a DOM tree or as SAX events. For example, by using StringWriter, you can marshal an object into a string. You can also marshal an object graph to a javax.xml.transform.Result object.

Here are some more examples of marshalling:

Marshalling to a file (FileOutputStream):

OutputStream os = new FileOutputStream( "xmlFile.xml" );
m.marshal( obj, os );				
					

Marshalling to a SAX ContentHandler:

// assume MyContentHandler instanceof ContentHandler
m.marshal( obj, new MyContentHandler() );  
					

Marshalling to a DOM Node:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();

m.marshal( obj, doc );
					

Marshalling to a java.io.OutputStream:

m.marshal( obj, System.out );
					

Marshalling to a java.io.Writer:

m.marshal( obj, new PrintWriter( System.out ) );					
					

Marshalling to a javax.xml.transform.SAXResult:

// assume MyContentHandler instanceof ContentHandler
SAXResult result = new SAXResult( new MyContentHandler() );

m.marshal( obj, result );
					

Marshalling to a javax.xml.transform.DOMResult:

DOMResult result = new DOMResult();
       
m.marshal( obj, result );
				    

Although each of the marshal methods accepts a java.lang.Object as its first parameter, JAXB Providers are not required to be able to marshal any arbitrary java.lang.Object. If the JAXBContext object that was used to create this Marshaller does not have enough information to know how to marshal the object parameter (or any objects reachable from it), then the marshal operation will throw a MarshalException.

By default, the Marshaller will use UTF-8 encoding when generating XML data to a java.io.OutputStream, or a java.io.Writer. Use the setProperty API to change the ouput encoding used during these marshal operations.

You can control the behavior of marshalling by setting Marshaller properties. For example, you can toggle indentation of the XML:

...					
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));					
...
					

JAXB can produce XML as SAX events. That is, you can pass ContentHandler and have it receive SAX events from a JAXB object. This gives client apps plenty of chances to modify XML. For example, you can add and remove elements or attributes, use one of the freely available serializers for better output, or write your own XML serializer that prints XML in your preferred way.

Finally, you can ask a Marshaller to marshal an invalid object graph by setting a ValidationEventHandler. If a provider supports error recovery, you can tell it to write XML even if it's incomplete.

If the boolean ValidationEventHandler.handleEvent(ValidationEvent event) method throws an unchecked runtime exception, the JAXB Provider must treat that as if the method returned false, effectively terminating whatever operation was in progress at the time (unmarshal, validate, or marshal). The method returns: true if the JAXB Provider should attempt to continue the current unmarshal, validate, or marshal operation after handling this warning/error, false if the provider should terminate the current operation with the appropriate UnmarshalException, ValidationException, or MarshalException.

Validation

There are three forms of Validation in JAXB:

  1. Unmarshal-Time Validation

    This form of validation enables a client application to receive information about validation errors and warnings detected while unmarshalling XML data into a Java content tree and is completely orthogonal to the other types of validation. To enable or disable it use method Unmarhaller.setValidating(...). All JAXB Providers are REQUIRED to support this operation.

  2. On-Demand Validation

    This form of validation enables a client application to receive information about validation errors and warnings detected in the Java content tree. At any point, client applications can call the Validator.validate(...) method on the Java content tree (or any sub-tree of it). All JAXB Providers are REQUIRED to support this operation.

  3. Fail-Fast Validation

    This form of validation enables a client application to receive immediate feedback about modifications to the Java content tree that violate type constraints on Java Properties as defined in the specification. JAXB Providers are NOT REQUIRED support this type of validation. Of the JAXB Providers that do support this type of validation, some may require you to decide at schema compile time whether or not a client application will be allowed to request fail-fast validation at runtime.

The Validator class is responsible for managing On-Demand Validation. The Unmarshaller class is responsible for managing Unmarshal-Time Validation during the unmarshal operations. Although there is no formal method of enabling validation during the marshal operations, the Marshaller may detect errors, which will be reported to the ValidationEventHandler registered on it.

JAXB has the capability to validate an object graph in memory without actually writing it to XML. This allows client apps to check if a graph is okay and ready to process; if not, validation will identify objects that contain errors so that, for example, client apps can ask users to fix those.

The following code validates the object "item":

...
JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
ObjectFactory itemMaker = new ObjectFactory();
Item item = itemMaker.createItem();
Validator validator = jaxbContext.createValidator();
if(! validator.validate(item)) {
	System.err.println("Not valid !!!");
}	
...
					

To receive detailed information about errors, you need to register ValidationEventHandler with the Validator, just like you did in Unmarshaller and Marshaller. This is analogous to registering an ErrorHandler for a SAX parser.

You can also first marshal an object graph and then validate XML (for example by Java API for validators). But doing so makes it much harder to associate errors with their sources, which makes debugging harder for humans. Validation after marshalling will give you errors like "missing <foo> element," but you can hardly know what is actually wrong in the object graph.

Validity is not enforced while you are modifying an object graph; you ALWAYS have to explicitly validate it. To edit a valid object graph into another valid object graph, you may need to go through invalid intermediate states. If validity is enforced on every step of mutation, this becomes impossible.

Customization Through the Schema

The binding language is an XML based language which defines constructs referred to as binding declarations. A binding declaration can be used to customize the default binding between an XML schema component and its Java representation.

The schema for binding declarations is defined in the namespace http://java.sun.com/xml/ns/jaxb. This specification uses the namespace prefix "jaxb" to refer to the namespace of binding declarations. For example:

					
<jaxb: binding declaration >

					

A binding compiler interprets the binding declaration relative to the source schema and a set of default bindings for that schema. Therefore a source schema need not contain a binding declarations for every schema component. This makes the job of a JAXB application developer easier.

There are two ways to associate a binding declaration with a schema element:

The syntax and semantics of the binding declaration is the same regardless of which of the above two methods is used for customization.

Inline Annotated Schema

This method of customization utilizes on the appinfo element specified by the XML Schema. A binding declaration is embedded within the appinfo element as illustrated below:

					
<xs:annotation>
  <xs:appinfo>
    <binding declaration>
  </xs:appinfo>
</xs:annotation>

					
The inline annotation where the binding declaration is used identifies the schema component.

Here are the changes you must make to the schema to make JAXB generate java.util.Vector rather than java.util.ArrayList, its default collection (the collecionType value must be either "indexed" or any fully qualified class name that implements java.util.List). Note that the top-level schema tag needs to be changed too:

					
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    jxb:version="1.0">
  ...
  <xs:annotation>
    <xs:appinfo>
      <jxb:globalBindings collectionType="java.util.Vector" />
    </xs:appinfo>
  </xs:annotation>
  ...

					
The annotation tag introduces a part of the schema that is usually intended for schema processing software. The appinfo tag introduces instructions for a particular processing application (in this case, JAXB's xjc code-generation tool). Usually, each application uses its own namespace, as JAXB has done here.

Before customization:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
  <xs:element name="todolist">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" minOccurs="0" name="item" type="entry"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  ...
</xs:schema>    
					
					
					
public class TodolistTypeImpl implements ... {

    protected com.sun.xml.bind.util.ListImpl _Item = new com.sun.xml.bind.util.ListImpl(new java.util.ArrayList());
    ...
}    
					

After customization:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    jxb:version="1.0">

  <xs:annotation>
    <xs:appinfo>
      <jxb:globalBindings collectionType="java.util.Vector" />
    </xs:appinfo>
  </xs:annotation>
    
  <xs:element name="todolist">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" minOccurs="0" name="item" type="entry"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  ...
</xs:schema>    
					
					
					
public class TodolistTypeImpl implements ... {

    protected com.sun.xml.bind.util.ListImpl _Item = new com.sun.xml.bind.util.ListImpl(new java.util.Vector());
    ...
}    
					

External Binding Declaration

The external binding declaration format enables customized binding without requiring modification of the source schema. Unlike inline annotation, the remote schema component to which the binding declaration applies must be identified explicitly. The jaxb:bindings element enables the specification of a remote schema context to associate its binding declaration(s) with. Minimally, an external binding declaration follows the following format:

					
<jaxb:bindings schemaLocation = "xs:anyURI">
  <jaxb:bindings node = "xs:string">*
    <binding declaration>
  <jaxb:bindings>
</jaxb:bindings>

					
The attributes schemaLocation and node are used to construct a reference to a node in a remote schema. The binding declaration is applied to this node by the binding compiler as if the binding declaration was embedded in the node’s xs:appinfo element. The attribute values are interpreted as follows:

Professional hosting     Belorussian informational portal         Free SCWCD 1.4 Study Guide     Free SCBCD 1.3 Study Guide     SCDJWS 1.4 Quiz     Free IBM Certified Associate Developer Study Guide     Free SCJP 5.0 (Tiger) Study Guide     Free Mock Exam Engine     IBM Test 000-287. Enterprise Application Development with IBM WebSphere Studio, V5.0 Study Guide     IBM Test 000-255. Developing with IBM Rational Application Developer for WebSphere Software V6 Study Guide