The objective of the Axis2Databinding framework is to provide a lightweight and simple schema compiler/ Java bean generator for Axis2. By no means it's to be a fully functional schema compiler like XMLBeans. This document aims to provide the architectural overview of the Axis2 Databinding Framework (referred to as ADB from here onwards) and be a guide to anyone who wants to use and modify ADB. Note that ADB is written in a fashion that allows it to be used as a standalone schema compiler and also to be extended to generate code for other languages.
ADB is built on a modular architecture that allows it to utilize a pre configured writer depending on the configuration.The 'big block diagram' for the code generator architecture is depicted below
ADB utilizes the WS-commons XmlSchema library for reading the Schema. The object model for the schema comes in the form of a XmlSchema object. The schema compiler keeps an instance of the writer (in the default case it's the JavaBeanWriter) which actually writes the classes. The writers may use whatever the technique they prefer, as in the case of the JavaBeanWriter, they use an XSLT template. The SchemaCompiler also uses a typemapper object that tells it what classnames to be used for the QNames that it encounters. This type mapper is also part of the configuration and the users can override the default type mapper by overriding the property setting.
As explained in the previous section, the schema compiler depends on the WS-Commons XmlSchema library. The XSLT transformations are dependent on the JVM's DOMimplementation (either crimson or xerces) which means that the underlying JVM should be 1.4 or higher. Apart from that ADB has no special dependencies on any other special jar files. The code for the schema compiler is completely in the org.apache.axis2.databinding.schema.* package. This package resides in the codegen module of the Axis2 source tree.
Following are the important classes and files
The easiest way to obtain the ADB binaries is to run the maven build for the codegen module. This will generate the codegen-{$version}.jar inside the target folder which is directly usable when the ADB schema compiler is required.
ADB comes with a mainclass XSD2Java that allows the schemas to be compiled just by giving the schema file reference.This main class is pretty much primitive and does not provide much control over the code generation process. This is bound to improve in the near future.
Code generator accepts the follwing parameters
Since the main class has no validations built in, the compiler is likely to cough up an unexpected error message if these parameters are not supplied properly.
This is the only way to harness the full potential of the schema compiler. The current Axis2 integration of ADB happens through this API. The most important classes and methods of the Schema compiler are as follows.
The constructor of the schema compiler expects a CompilerOptions object. This compilerOptions object is more of a holder for the parameters that are passed to the SchemaCompiler. The only mandatory parameter in the CompilerOptions is the output directory
The compile method to call for a single schema. The expected object is a XMLSchema which is part of the XmlSchema library.
Similar to the previous method but accepts a list of schemas instead of one.
For a comprehensive code sample in invoking the schema compiler throught the API, the following classes would be helpful
When the schema compiler is invoked (oneway or another) it generates code depending on the following rules
Once the code is generated according to the rules it looks like the following. Consider the follwing piece of schema
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://soapinterop.org/types" targetNamespace="http://soapinterop.org/types"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="SOAPStruct"> <sequence> <element name="varString" type="xsd:string"/> <element name="varInt" type="xsd:int"/> <element name="varFloat" type="xsd:float"/> </sequence> </complexType> <element name="myElement" type="tns:SOAPStruct"/> </schema>
This particular schema generates the following two classes in the designated package. This package is derived from the target Namespace of the schema.
As explained earlier, SOAPStruct refers to the complexType. MyElement is the class that refers to the element.Just as expected, the SOAPStruct bean has getters and Setters for varString,varInt and varFloat which are a String,an int and a float respectively.myElement on the other hand has a single field representing the SOAPStruct object that it encapsulates.
The most important aspect of the generated code is that it encapsulates two methods for creation and serializing the beans.Note that to make this work, the generated beans implement the org.apache.axis2.databinding.ADBBean interface
The creator and reader methods look like the following
public javax.xml.stream.XMLStreamReader getPullParser(javax.xml.namespace.QName qName)
This method returns a pull parser that throws the right events for this particular object. However there is a subtle difference between element based classes and complexType based classes
public static [Object] parse(javax.xml.stream.XMLStreamReader reader) throws java.lang.Exception
This method returns a populated instance of the class in question.(Note that
[Object]will be replaced by the actual class that contains this method. Say for SOAPStruct the method looks like
public static SOAPStruct parse(javax.xml.stream.XMLStreamReader reader) throws java.lang.Exception
Consider the follwing XML fragment
<myElement> <varInt>5</varInt> <varString>Hello</varString> <varFloat>3.3</varFloat> </myElement>
Enthusiastic readers might already have figured out that this piece of XML complies to the Schema mentioned above. The following piece of code shows how to build a populated instance of myElement with this fragment of XML
XMLStreamReader reader = XMLInputFactory.newInstance(). createXMLStreamReader( new ByteArrayInputStream(xmlString.getBytes())); myElement elt = myElement.parse(reader);
Although this example takes on the tedious effort of creating a reader out of the String, inside the Axis2 environment an XMLStreamReader can be direclty asked from the OMElement! Hence the parse method becomes a hugh advantage for hassle free object creation.
Similarly the reader obtained from the object can also be utilized as needed. The following code fragment shows how to utilize the getPullParser method to create an OMElement
XMLStreamReader reader = elt.getPullParser(null); OMElement omElt = new StAXOMBuilder(reader).getDocumentElement();
That's all to it! If you are interested in learning more on ADB the following documents may also be helpful