1) Introduction
The first part of this article listed out the major new features of Java 6 (Mustang) related to areas like Common Annotations (JSR 250), Scripting Language for the Java Platform (JSR 223) and JDBC 4.0. This article assumed that Readers have got sufficiently fair bit of knowledge in the various concepts of Java 5.0. First-time Readers of Java 6 are strongly encouraged to read the first part of this article titled “Introduction to Java 6.0 New Features, Part–I”. This article covers the left-over features of Part-I. More specifically, it will cover the Pluggabable Annotation Processing API (JSR 269), Java API for XML Binding (JSR 222) and Streaming API for XML (JSR 173).
also read:
2) Pluggable Annotation Processing API
2.1) Introduction to Annotation
Annotations have been there in the Java World from Java 5.0. Java Annotations are a result of the JSR 175 which aimed in providing a Meta-Data Facility to the Java Programming Language. It can be greatly used by the Build-time Tools and Run-time Environments to do a bunch of useful tasks like Code Generation, Validation and other valuable stuffs. Java 6 has introduced a new JSR called JSR 269, which is the Pluggable Annotation Processing API. With this API, now it is possible for the Application Developers to write a Customized Annotation Processor which can be plugged-in to the code to operate on the set of Annotations that appear in a Source File.
Let us see in the subsequent sections how to write a Java File which will make use of Custom Annotations along with a Custom Annotation Processor to process them.
2.2) Writing Custom Annotations
This section provides two Custom Annotations which will be used by a Sample Java File and a Custom Annotation Processor. One is the Class Level Annotation and the other is the Method Level Annotation. Following is the listing for both the Annotation Declarations. See how the Targets for the Annotations ClassLevelAnnotation.java and MethodLevelAnnotation.java are set to ElementType.TYPE and ElementType.METHOD respectively.
ClassLevelAnnotation.java
package net.javabeat.articles.java6.newfeatures.customannotations; import java.lang.annotation.*; @Target(value = {ElementType.TYPE}) public @interface ClassLevelAnnotation { }
MethodLevelAnnotation.java
package net.javabeat.articles.java6.newfeatures.customannotations; import java.lang.annotation.*; @Target(value = {ElementType.METHOD}) public @interface MethodLevelAnnotation { }
AnnotatedJavaFile.java
package net.javabeat.articles.java6.newfeatures.customannotations; @ClassLevelAnnotation() public class AnnotatedJavaFile { @MethodLevelAnnotation public void annotatedMethod(){ } }
The above is a Sample Java File that makes use of the Class Level and the Method Level Annotations. Note that @ClassLevelAnnotation is applied at the Class Level and the @MethodLevelAnnotation is applied at the method Level. This is because both the Annotation Types have been defined to be tagged to these respective Elements only with the help of @Target Annotation.
2.3) Writing a Simple Custom Annotation Processor
TestAnnotationProcessor.java
package net.javabeat.articles.java6.newfeatures.customannotations; import java.util.*; import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; @SupportedAnnotationTypes(value= {"*"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) public class TestAnnotationProcessor extends AbstractProcessor { @Override public boolean process( Set<?> extends TypeElement> annotations, RoundEnvironment roundEnv){ for (TypeElement element : annotations){ System.out.println(element.getQualifiedName()); } return true; } }
Let us discuss the core points in writing a Custom Annotation Processor in Java 6. The first notable thing is that Test Annotation Processor class extends AbstractProcessor class which encapsulates an Abstract Annotation Processor. We have to inform what Annotation Types our Test Annotation Processor Supports. This is manifested through the Class-Level Annotation called @SupportedAnnotationTypes(). A value of “*” indicates that all types of Annotations will be processed by this Annotation Processor. Which version of Source Files this Annotation Processor supports is mentioned through @SupportedSourceVersion Annotation.
The javac compiler of Mustang has an option called ‘-processor’ where we can specify the Name of the Annotation Processor along with a Set of Java Source Files containing the Annotations. For example, in our case, the command syntax would be something like the following,
javac -processor net.javabeat.articles.java6.newfeatures.customannotations.TestAnnotationProcessor AnnotatedJavaFile.java
The above command tells that the name of the Annotation Processor is net.javabeat.articles.java6.newfeatures.customannotations.TestAnnotationProcessor and it is going to process the AnnotatedJavaFile.java. As soon as this command is issued in the console, the TestAnnotationProcessor.process() method will be called by passing the Set of Annotations that are found in the Source Files along with the Annotation Processing Information as represented by RoundEnvironment. This TestAnnotationProcessor just list the various Annotations present in the Sample Java File (AnnotatedJavaFile.java) by iterating over it.
Following is the output of the above program
net.javabeat.articles.java6.newfeatures.customannotations.ClassLevelAnnotation net.javabeat.articles.java6.newfeatures.customannotations.MethodLevelAnnotation
3) Streaming API for XML
3.1) Introduction
Streaming API for XML, simply called StaX, is an API for reading and writing XML Documents. Why need another XML Parsing API when we already have SAX (Simple API for XML Parsing) and DOM (Document Object Model)? Both SAX and DOM parsers have their own advantages and disadvantages and StaX provides a solution for the disadvantages that are found in both SAX and DOM. It is not that StaX replaces SAX and DOM.
SAX, which provides an Event-Driven XML Processing, follows the Push-Parsing Model. What this model means is that in SAX, Applications will register Listeners in the form of Handlers to the Parser and will get notified through Call-back methods. Here the SAX Parser takes the control over Application thread by Pushing Events to the Application. So SAX is a Push-Parsing model. Whereas StaX is a Pull-Parsing model meaning that Application can take the control over parsing the XML Documents by pulling (taking) the Events from the Parser.
The disadvantage of DOM Parser is, it will keep the whole XML Document Tree in memory and certainly this would be problematic if the size of the Document is large. StaX doesn’t follow this type of model and it also has options for Skipping a Portion of a large Document during Reading.
The core StaX API falls into two categories and they are listed below. They are
- Cursor API
- Event Iterator API
Applications can any of these two API for parsing XML Documents. Let us see what these APIs’ are in detail in the following sections.
3.2) Cursor API
The Cursor API is used to traverse over the XML Document. Think of a Cursor as some kind of Pointer pointing at the start of the XML Document and then Forwarding the Document upon properly instructed. The working model of this Cursor API is very simple. When given a XML Document and asked to parse, the Parser will start reading the XML Document, and if any of the Nodes (like Start Element, Attribute, Text, End Element) are found it will stop and will give information about the Nodes to the Processing Application if requested. This cursor is a Forward only Cursor, it can never go backwards. Both Reading and Writing operations is possible in this cursor API.
3.3) Sample Application
Let us consider a sample Application which will read data from and to the XML Document with the help of the Cursor API. Following is the sample XML Document. The below XML File contains a list of Events for a person in his/her Calendar.
myCalendar.xml
<calendar> <event type = "meeting"> <whom>With my Manager</whom> <where>At the Conference Hall</where> <date>June 09 2007</date> <time>10.30AM</time> </event> <event type = "birthday"> <whom>For my Girl Friend</whom> <date>01 December</date> </event> </calendar>
ReadingUsingCursorApi.java
package net.javabeat.articles.java6.newfeatures.stax; import java.io.*; import javax.xml.stream.*; import javax.xml.stream.events.*; public class ReadingUsingCurorApi { private XMLInputFactory inputFactory = null; private XMLStreamReader xmlReader = null; public ReadingUsingCurorApi() { inputFactory = XMLInputFactory.newInstance(); } public void read() throws Exception{ xmlReader = inputFactory.createXMLStreamReader( new FileReader(".\\src\\myCalendar.xml")); while (xmlReader.hasNext()){ Integer eventType = xmlReader.next(); if (eventType.equals(XMLEvent.START_ELEMENT)){ System.out.print(" " + xmlReader.getName() + " "); }else if (eventType.equals(XMLEvent.CHARACTERS)){ System.out.print(" " + xmlReader.getText() + " "); }else if (eventType.equals(XMLEvent.ATTRIBUTE)){ System.out.print(" " + xmlReader.getName() + " "); }else if (eventType.equals(XMLEvent.END_ELEMENT)){ System.out.print(" " + xmlReader.getName() + " "); } } xmlReader.close(); } public static void main(String args[]){ try{ ReadingUsingCurorApi obj = new ReadingUsingCurorApi(); obj.read(); }catch(Exception exception){ exception.printStackTrace(); } } }
XMLInputFactory is the Factory Class for creating Input Stream objects which is represented by XMLStreamReader. An instance of type XMLStreamReader is created by calling XMLInputFactory.createXMLStreamReader() by passing the XML File to be parsed. At this stage, the Parser is ready to read the XML Contents if a combination call to XMLStreamReader.hasNext() and XMLStreamReader.next() is made. The entire Document is traversed in the while loop and the appropriate node’s value is taken by checking the various Element Types.
3.4) Event Iterator API
The Working Model of this Event Iterator API is no more different from the Cursor API. As the Parser starts traversing over the XML Document and if any of the Nodes are found, it will provide this information to the Application that is processing in the form of XML Events. Applications can loop over the entire Document, by requesting for the Next Event. This Event Iterator API is implemented on top of Cursor API.
3.5) Sample Application
Now let us take over a Sample Application using the Event Iterator API which is parsing on the XML Document myCalendar.xml.
ReadingUsingEventIterator.java
package net.javabeat.articles.java6.newfeatures.stax; import java.io.*; import javax.xml.stream.*; import javax.xml.stream.events.*; public class ReadingUsingEventIteratorApi { private XMLInputFactory inputFactory = null; private XMLEventReader xmlEventReader = null; public ReadingUsingEventIteratorApi() { inputFactory = XMLInputFactory.newInstance(); } public void read() throws Exception{ xmlEventReader = inputFactory.createXMLEventReader( new FileReader(".\\src\\myCalendar.xml")); while (xmlEventReader.hasNext()){ XMLEvent xmlEvent = xmlEventReader.nextEvent(); if (xmlEvent.isStartElement()){ System.out.print(" " + xmlEvent.asStartElement().getName() + " "); }else if (xmlEvent.isCharacters()){ System.out.print(" " + xmlEvent.asCharacters().getData() + " "); }else if (xmlEvent.isEndElement()){ System.out.print(" " + xmlEvent.asEndElement().getName() + " "); } } xmlEventReader.close(); } public static void main(String args[]){ try{ ReadingUsingEventIteratorApi obj = new ReadingUsingEventIteratorApi(); obj.read(); }catch(Exception exception){ exception.printStackTrace(); } } }
If XMLStreamReader class represents the Reader for stream reading the XML Contents, then XMLEventReader represents the class for reading the XML Document as XML Events (represented by javax.xml.stream.events.XMLEvent). The rest of the reading logic is the same as that of the ReadingUsingCurorApi.java.
4) Conclusion
This article covered the leftover features of the Part I New features of Java 6. Starting with Pluggable Annotation Processing API, it covered what Annotations are, then guided us how to write Custom Annotations and Custom Annotation Processor. Then it traversed over the Cursor API and the Event Iterator API of StaX such as how to read XML Documents along with well-defined samples. Finally through Java API for XML Binding, it details how to map Java and XML Documents with some sample applications.