Incremental Compilation and Error Handling in XMLBeansby Hetal Shah AbstractXMLBeans version 2.1.0 provides programmatic access to create and update XMLBeans from schema artifacts, and to validate and capture errors that may occur during schema compilation and parsing of an XML document. In any enterprise applications ranging from Web service client/server to CRM and EAI products, as products mature the need arises to update existing schema artifacts. Moreover, everyone wants to simplify the maintenance of applications processing XML documents based on these schema artifacts. The XMLBeans API provides a simple and efficient way to create and maintain XMLBeans and offers rich custom error handling and reporting capabilities, both contributing to solving these problems. This article illustrates these features with a series of examples. It assumes you have a familiarity with XMLBeans. For an XMLBeans primer, see the References section. The example code and other files mentioned in this article are available for download. IntroductionJava-based enterprise applications often use Java-XML binding libraries as an underlying layer to access and process XML data in a familiar, Java friendly way. Using XMLBeans has become popular as a Java-XML binding solution because of its unique features such as lazy unmarshalling, cursor-based access to XML data, and support for XQuery. You create XMLBeans by running XMLBeans are composed of a set of Java binding classes and a bunch of XSB files containing binary schema metadata compiled from the schema documents. Each of the XSB files represents a compiled schema type, an attribute, or an element definition. The
The With this background established, let's now look at the
The
Schema CompilationNow that I have described how useful programmatic access to XMLBeans can be and what the main methods for compiling beans are, let's put it all into practice by compiling the sample schema Listing 1: This excerpt from
XmlObject[] schemaObj = new XmlObject[]
{XmlObject.Factory.parse(new File(args[0]))};
SchemaTypeSystem schemaTypeObj =
XmlBeans.compileXmlBeans(null, null, schemaObj,
null, null, null, null);
// get list of global elements
SchemaGlobalElement globalElementsArray[] =
schemaTypeObj.globalElements();
..
// get list of global attributes
SchemaGlobalAttribute globalAttributesArray[] =
schemaTypeObj.globalAttributes();
....
Here, the schema is parsed by the Generating XMLBeansNow that you have seen how to compile a schema, the next logical step is to see how XMLBeans files are created from the schema with the help of the interface class
Of course, generated Java files need to be later compiled and packaged in a JAR file along with XSB files. The sample code for this article contains a concrete class Listing 2: This is an excerpt of the sample concrete class
public class FilerImpl implements Filer{
....
FilerImpl (String folderPath) {
this.folderPath = folderPath;
}
public OutputStream createBinaryFile(String name)
throws IOException {
File fileObj = new File(folderPath, name);
....
return new FileOutputStream(fileObj);
}
public Writer createSourceFile(String name)
throws IOException {
...
File fileObj=
new File(folderPath, name + ".java");
...
return new FileWriter(fileObj);
}
public boolean compileJavaFiles() {
...
for (int i=0; i>javaFilePaths.size();i++){
String[] args = new String[] {"-classpath"
,System.getProperty("java.class.path",".") ,
"-d", folderPath,
(String) javaFilePaths.elementAt(i)};
status = javac.compile(args);
}
...
}
public boolean makeJarFile(String jarFile)
throws IOException {
...
jarHelperObj.jarDir(new File(folderPath),
fileObj);
...
}
public boolean extractJarFile(String jarFile,
String destDir)
throws IOException {
...
jarHelperObj.unjarDir(fileObj,dirObj);
...
}
public String prependToClassPath(String filePath)
throws IOException {
String classPath =
System.getProperty("java.class.path",".");
System.setProperty("java.class.path",
filePath + ";" + classPath);
...
}
}
Now to compile the sample schema Listing 3: This excerpt from
FilerImpl flrObj =
new FilerImpl("outputDIR");
XmlObject[] schemaObj = new XmlObject[]
{XmlObject.Factory.parse(new File(args[0]))};
SchemaTypeSystem schemaTypeObj =
XmlBeans.compileXmlBeans("location", null,
schemaObj, null, null, flrObj, null);
flrObj.compileJavaFiles();
flrObj.makeJarFile("outputDIR\\locationXB.jar");
Updating XMLBeansXML schemas will change over time either due to the evolution of data in an enterprise application, or because of an upgrade of the Web service interface. With each new version of XML schema, corresponding XML instance documents and applications processing those XML documents need to be evolved and updated. If changes are made in the original schema document, then a programmatic implementation of updating the corresponding XMLBeans is simple and similar to Listing 3 discussed in the previous section—that is, recompile the entire schema and recreate the XMLBeans files from it. XMLBeans also supports incremental compilation that involves recompiling only what is necessary to bring the beans up to date with the schema in the shortest time possible. XMLBeans supports incremental compilation by updating existing beans from schema artifacts containing either new schema definitions, or through modification to existing definitions or deletions of already compiled schema definitions. Incremental Compilation Now I will add a new global element Latlong declared in the sample, Listing 4: This excerpt from
..
<xsd:element name="Weather">
<xsd:complexType>
<xsd:sequence>
...
<xsd:element name="FeelsLike"
type="xsd:float"/>
...
<xsd:element name="Visibility"
type="xsd:float"/>
...
</xsd:complexType>
</xsd:element>
The excerpt shown in Listing 5 prepends the path of a JAR file containing XMLBeans to the system property Listing 5: An excerpt from
class IncrementalCompilation{
...
public static void main(String args[]) {
...
flrObj.extractJarFile(
args[oldJARFileArgPosition],
args[outputFolderPathPosition] );
flrObj.prependToClassPath(
args[outputFolderPathPosition]);
SchemaTypeLoader stl =
XmlBeans.typeLoaderUnion(
new SchemaTypeLoader[]
{ XmlBeans.getContextTypeLoader(),
XmlBeans.getBuiltinTypeSystem() });
...
for (int i =updatedXSDFileArgPosition,
j=0; j < updatedXSDDefinitionsSize;
i++,j++ ) {
updatedXSDObj[j] =
XmlObject.Factory.parse(
new File(args[i]),options);
}
augSTSObj = XmlBeans.compileXmlBeans(null,
null,updatedXSDObj , null,
stl, flrObj, options);
}
flrObj.compileJavaFiles();
flrObj.makeJarFile(args[newJARFileArgPosition]);
...
}
java -classpath %CLASSPATH%;.\outputDIR\locationXB.jar; IncrementalCompilation outputDIR outputDIR\locationXB_IncrementalCompilation.jar outputDIR\locationXB.jar location_add.xsd location_modify.xsd The JAR file created by XML Schema ValidationXMLBeans validates the schema document when compiling using If a schema is not valid, then XMLBeans throws an
Now that you are familiar with validation and error handling APIs, let's put them into use by parsing an invalid sample schema location_invalid.xsd. I'll show you how to handle validation error and generate custom error message en route. Listing 7 shows how to catch Listing 7: An excerpt from
class CustomErrorSample{
public static void main(String args[]) {
Collection errorList = new ArrayList();
XmlOptions parseOptionsObj = new XmlOptions();
parseOptionsObj.setLoadLineNumbers();
parseOptionsObj.setLoadLineNumbers(
XmlOptions.LOAD_LINE_NUMBERS_END_ELEMENT);
XmlOptions loadOptionsObj = new XmlOptions();
loadOptionsObj.setErrorListener(errorList);
try {
XmlObject[] schemaObj = new XmlObject[]
{XmlObject.Factory.parse(
new File(args[0]),parseOptionsObj)};
SchemaTypeLoader schemaTypeObj =
XmlBeans.loadXsd(schemaObj,
loadOptionsObj);
}catch (XmlException xme) {
CustomErrorHandlingUtil eUtilObj =
new CustomErrorHandlingUtil();
eUtilObj.handleXMLException(xme);
Collection userErrors =
(Collection)loadOptionsObj.get(
XmlOptions.ERROR_LISTENER);
eUtilObj.handleErrorCollection(
userErrors);
}
....
}
In the above code, two different instances of XML Document ValidationBy default, XMLBeans does not perform complete validation of an XML instance document during parsing or while updating XMLBeans instances. However, an application can invoke one of the overloaded
The
As an example, say the Listing 8: An excerpt of
public class WeatherUnmarshal {
public static void main(String args[]) {
ArrayList errorList = new ArrayList();
...
optionsObj.setErrorListener(errorList);
try {
...
WeatherDocument weatherDoc =
WeatherDocument.Factory.parse(
inputXMLFile,optionsObj);
if (weatherDoc.validate(optionsObj)) {
....
} else {
// Invalid xml document.
...
customErrorHandlingUtil eUtilObj =
new customErrorHandlingUtil();
eUtilObj.handleErrorCollection(errorList);
}
}
}
If the XML instance document is invalid, then the custom error handling is invoked using the helper class DownloadThe examples have been tested with Apache XMLBeans version 2.1.0 and JDK version 1.5.0_06, and contain sample schema, Java code, and XML files used in this article:
SummaryThis article began by discussing the challenges of automating and simplifying the maintenance of enterprise applications processing XML documents as the underlying schema evolves. We learned about the programmatic access provided by the XMLBeans API to create and update XMLBeans when the XML schema is changed. Along the way I showed that XMLBeans' support for incremental compilation, which facilitates team-based design and reduces compile time, results in a significant gain when an enterprise application becomes larger and more complex. I also looked at the validation and error handling features of XMLBeans for schemas and XML instance documents. Validation features of XMLBeans provide fine control over the compile time validation of schema and validation of XML documents and bean instances. XMLBeans error handling features are available for customizing the error message reporting. References
Hetal Shah is an IT consultant who is highly passionate about Internet-related technologies. Return to dev2dev. |
Article Tools Related Products Check out the products mentioned in this article:Related Technologies Related Articles Bookmark Article
|