CSC/ECE 517 Fall 2010/ch2 S24 NS: Difference between revisions
(46 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= | =Metaprogramming in statically typed languages= | ||
==What is Metaprogramming?== | ==What is Metaprogramming?== | ||
Metaprogramming is the technique that allows us to write programs that can manipulate other programs or themselves as a part of their data. Such programs help the programmer to avoid recompilations by executing their part of the work at compile time rather than runtime. | Metaprogramming is the technique that allows us to write programs that can manipulate other programs or themselves as a part of their data. Such programs help the programmer to avoid recompilations by executing their part of the work at compile time rather than at runtime. | ||
The ability of a program to treat itself as a part of the data is known as reflection by virtue of which the program can modify its own structure and behavior. Often, metaprogramming and reflection are synonymous terms and one can be defined in the context of the other. Metalanguage is the language in which the metaprogram is written. | The ability of a program to treat itself as a part of the data is known as reflection by virtue of which the program can modify its own structure and behavior. Often, metaprogramming and reflection are synonymous terms and one can be defined in the context of the other. Metalanguage is the language in which the metaprogram is written. | ||
Line 11: | Line 11: | ||
==Example of Metaprogramming== | ==Example of Metaprogramming== | ||
The following figure applies the concept of Metaprogramming to the Ruby programming language | |||
[[Image:Metapic.png|frame|center]] | |||
The attributes of the File entity are redefined and modified at runtime using the expressions of the programming language. | |||
Now let us take another aspect of Metaprogramming in the same ruby language. Supposing we are having the following code in our ruby file. | |||
COLORS = { :black => "000", | COLORS = { :black => "000", | ||
Line 20: | Line 26: | ||
:magenta => "f0f", | :magenta => "f0f", | ||
:cyan => "0ff", | :cyan => "0ff", | ||
:white => "fff" } | :white => "fff" | ||
} | |||
The class can be defined as | |||
class String | |||
COLORS.each do |color,code| | |||
define_method "in_#{color}" do "<span style=\"color: ##{code}\">#{self}</span>" | |||
end | |||
end | end | ||
end | end | ||
The above code generates new methods for the build in String class based on a list of colors and they wrap the particular String in the respective color by virtue of HTML tags. | The above code generates new methods for the build in String class based on a list of colors and they wrap the particular String in the respective color by virtue of HTML tags. | ||
Line 49: | Line 57: | ||
===Reflection in Java=== | ===Reflection in Java=== | ||
The reflective nature of a | The reflective nature of a Java program allows Java programs to introspect upon themselves and manipulate internal properties of the program. One tangible use of this feature is in JavaBeans in which a information about the classes are dynamically obtained via a Builder Tool as the classes are dynamically loaded. Reflection in Java is normally accomplished through the Reflection API which consists of the "Reflect" package and is available in the java.lang hierarchy. | ||
Consider the following code | Consider the following code | ||
Line 68: | Line 76: | ||
} | } | ||
} | } | ||
If it is invoked in the following manner | If it is invoked in the following manner | ||
“java DumpMethods java.util.Stack” | |||
The output will be: | The output will be: | ||
public java.lang.Object java.util.Stack.push( | public java.lang.Object java.util.Stack.push( | ||
java.lang.Object) | |||
public synchronized | |||
java.lang.Object java.util.Stack.pop() | |||
public synchronized | public synchronized | ||
java.lang.Object java.util.Stack.peek() | java.lang.Object java.util.Stack.peek() | ||
public boolean java.util.Stack.empty() | public boolean java.util.Stack.empty() | ||
public synchronized | public synchronized | ||
int java.util.Stack.search(java.lang.Object) | int java.util.Stack.search(java.lang.Object) | ||
Line 97: | Line 106: | ||
===Generics in Java=== | ===Generics in Java=== | ||
public class BoxingGenericsExample { | Generic programming is a type of computer programming in which the algorithms are written to accommodate data types whose values are to be specified late. Such data types are instantiated only when the particular datatype is passed as a parameter to the Generic class. | ||
In Java, code is not created for each type specific instance of a Generic like other statically typed languages like C++. Bytecode is generated only once for each function and class and the generic types are replaced by “Object”, which is a built in generic type. | |||
====How Generics are defined?==== | |||
Consider the use of the List class to define generics. Then, it can be defined as | |||
List <WrapperClass type> object = new ArrayList <WrapperClass type> | |||
Wrapper Class may be String or Integer or similar class types based on the requirement | |||
An example of the use of Generics is as follows | |||
import java.util.*; | |||
public class BoxingGenericsExample { | |||
public static void main(String args[]) | |||
{ | |||
HashMap<String,Integer> hm = new HashMap<String,Integer>(); | HashMap<String,Integer> hm = new HashMap<String,Integer>(); | ||
hm.put("speed", 20); | hm.put("speed", 20); | ||
} | |||
} | } | ||
The HashMap can accommodate two values of String and Integer types which are declared using Generics | The HashMap can accommodate two values of String and Integer types which are declared using Generics | ||
====Generic Classes==== | |||
It is possible to define classes in Generics | It is possible to define classes in Generics | ||
class GenericExample<T> { | |||
{ | T ob; // declare an object of type T | ||
GenericExample(T o) //constructor initializing the object of T to the object passed as args | |||
{ | |||
ob = o; | ob = o; | ||
} | |||
T getob() { | |||
return ob; | |||
} | |||
void showType() { | |||
System.out.println("Type of T is " + ob.getClass().getName()); | |||
} | |||
} | |||
public class GenDemo { | |||
public static void main(String args[]) { | |||
GenericExample<Integer> iOb= new GenericExample<Integer>(88); | |||
iOb.showType(); | |||
}} | |||
At runtime the value of T will be the Integer class | |||
====Generic Interfaces and Methods==== | |||
Similarly it is also possible to define interfaces and methods in Generics | |||
public interface List<E> { | |||
void add(Ex); | |||
void display(); | |||
} | |||
//Generic Method | |||
public static <T> void filter() | |||
{ | |||
//Method code | |||
} | |||
//Generic Method | |||
public static <T> void filter() | |||
{ | |||
//Method code | |||
} | |||
The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code so | The main disadvantages of Generics are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code so runtime safety is compromised. | ||
===Annotations in Java=== | ===Annotations in Java=== | ||
Line 169: | Line 188: | ||
====@Deprecated==== | ====@Deprecated==== | ||
The annotated element is deprecated and no longer in use. | The annotated element is deprecated and no longer in use. | ||
//Example of a deprecated annotation | //Example of a deprecated annotation | ||
@Deprecated | @Deprecated | ||
static void deprecatedMethod() | |||
{ | |||
//code | |||
} | |||
====@Override==== | ====@Override==== | ||
The annotated element is meant to be overridden in the superclass | The annotated element is meant to be overridden in the superclass | ||
//Example of a override annotation | //Example of a override annotation | ||
@Override | @Override | ||
int overriddenMethod() | |||
{ | |||
//code } | |||
====@SuppressWarnings==== | ====@SuppressWarnings==== | ||
The compiler has to suppress warnings which it would otherwise generate. This is usually done when a deprecated method is used and warnings from the compiler are not desired. | The compiler has to suppress warnings which it would otherwise generate. This is usually done when a deprecated method is used and warnings from the compiler are not desired. | ||
//Example of a suppress warning annotation | //Example of a suppress warning annotation | ||
// compiler not to generate a warning | // compiler not to generate a warning | ||
@SuppressWarnings("deprecation") | |||
void useDeprecatedMethod() { | |||
objectOne.deprecatedMethod(); //deprecation warning - suppressed | |||
} | |||
=Technical issues: Meta Programming with JAVA= | |||
=Technical issues: Meta Programming with JAVA | Every time a user wishes to write a Java Bean object, following key steps should be implemented. This includes: | ||
Every time a user wishes to write a Java Bean object, following key steps should be implemented. This includes | |||
*Making the class serializable | |||
*Ensuring the class has a default constructor | |||
*Writing getters and/or setters for all properties | |||
*Writing methods to register and unregister listeners for the bound properties | |||
Unit tests are seldom written for getters and setters and generally the process is error prone. | Unit tests are seldom written for getters and setters and generally the process is error prone. | ||
These shortcomings are overcome by code generating tools like | These shortcomings are overcome by code generating tools like XDoclet and Eclipse but they have their own limitations.All these tools use their own template language and their functionality is restricted to the behaviour of C/C++ macros. | ||
In a metaprogramming language, the template and the code it generates are implemented in one language only. It is therefore possible to extend the language itself, by adding new constructs, rather than developing the object hierarchy. | In a metaprogramming language, the template and the code it generates are implemented in one language only. It is therefore possible to extend the language itself, by adding new constructs, rather than developing the object hierarchy. | ||
==How to resolve this problem?== | ==How to resolve this problem?== | ||
===Attribute oriented programming=== It is a program-level marking technique to be exploited to enable meta programming and address the challenges posed by it. Programmers can mark elements like classes and methods to indicate that they maintain application-specific or domain-specific semantics. Application's business logic is separated from domain specific semantics using attributes. By keeping the implementation details of those semantics from program code hidden, attributes increase the level of abstraction and reduce programming complexity. This results in simpler and more readable programs. The program elements associated with attributes are transformed to more detailed programs by a supporting tool. A supporting tool can be a preprocessor. | ===Attribute oriented programming=== | ||
===XDoclet=== | It is a program-level marking technique to be exploited to enable meta programming and address the challenges posed by it. Programmers can mark elements like classes and methods to indicate that they maintain application-specific or domain-specific semantics. Application's business logic is separated from domain specific semantics using attributes. By keeping the implementation details of those semantics from program code hidden, attributes increase the level of abstraction and reduce programming complexity. This results in simpler and more readable programs. The program elements associated with attributes are transformed to more detailed programs by a supporting tool. A supporting tool can be a preprocessor. | ||
Users can add more meaning to the code by adding meta data to the java source code in special JavaDoc tags. This technique, also referred as Attribute Oriented Programming is made possible in Java by XDoclet, | |||
XDoclet has several advantages that has made it an instant hit with the programming community. | ====XDoclet==== | ||
Redundancy elimination: Users need to write only the business logic and XDoclet generates the support code and “boiler-plate” for it. | Users can add more meaning to the code by adding meta data to the java source code in special JavaDoc tags. This technique, also referred as Attribute Oriented Programming, is made possible in Java by XDoclet, an open source code generation engine. XDoclet works by parsing the source file and generating several artifacts from it. Artifacts can include XML descriptors and/or source code. Using the information provided in the source code and in its JavaDoc tags, template generate these files. XDoclet includes a core module and constantly growing number of modules. Whenever there is a requirement for a new component, new modules can be written easily using this feature. | ||
Extensibility: XDoclet is designed for modular programming. On identifying repeatable code, users can write XDoclet templates to generate the necessary code. | XDoclet has several advantages that has made it an instant hit with the programming community. A few advantages are | ||
Better understanding of J2EE programs: Users need to implement the enterprise bean and XDoclet generates the necessary interfaces, value objects, struts for the user. | *Redundancy elimination: Users need to write only the business logic and XDoclet generates the support code and “boiler-plate” for it. | ||
*Extensibility: XDoclet is designed for modular programming. On identifying repeatable code, users can write XDoclet templates to generate the necessary code. | |||
*Better understanding of J2EE programs: Users need to implement the enterprise bean and XDoclet generates the necessary interfaces, value objects, struts for the user. | |||
XDoclet was initially conceived as tool for creating EJBs. Over the course of time, it has evolved into a code generation engine making programming a lot easier. | XDoclet was initially conceived as tool for creating EJBs. Over the course of time, it has evolved into a code generation engine making programming a lot easier. | ||
public class Matrix | public class Matrix | ||
{ | { | ||
/** @todo need to handle the case where there is no spoon */ | /** @todo need to handle the case where there is no spoon */ | ||
public void reload() { | public void reload() { | ||
// … }} | // … }} | ||
Now to use the XDoclet code we have to insert a todo tag in the Ant Build file like the following | Now to use the XDoclet code we have to insert a todo tag in the Ant Build file like the following | ||
===Metadata Facility=== | <target name="todo" | ||
depends="init"> | |||
<documentdoclet destdir="todo"> | |||
<fileset dir="${dir.src}"> | |||
<include name="**/*.java" /> | |||
Prior to the release of the Metadata Facility, XDoclet was used for attribute oriented programming approach in Java. | |||
====Metadata Facility==== | |||
An advanced and a sophisticated technique for Attribute Oriented Programming in Java is through the Metadata Facility (JSR-175) [14] which is included in the J2SE version 5.0. It is actually an API (Application Programming Interface) for enabling annotations of fields, methods and classes and thus enabling developement tools and runtime libraries to run them in a specific desired way. | An advanced and a sophisticated technique for Attribute Oriented Programming in Java is through the Metadata Facility (JSR-175) [14] which is included in the J2SE version 5.0. It is actually an API (Application Programming Interface) for enabling annotations of fields, methods and classes and thus enabling developement tools and runtime libraries to run them in a specific desired way. | ||
=References= | |||
[1] Lindegren, Patrik and Ostlund, Joakim,'' Metaprogramming in Java, C# and C++'', 24th May, 2006 | |||
[2] Metaprogramming in Ruby, Retrieved September 21st , 2010, from Wikipedia page: http://en.wikipedia.org/wiki/Ruby_(programming_language)#Metaprogramming | |||
[3] Attribute Oriented Programming, Retrieved September 21st, 2010, from the Wikipedia page :http://en.wikipedia.org/wiki/Attribute-Oriented_Programming | |||
[4] Generics, Retrieved September 21st, 2010, from the Oracle Homepage:http://download.oracle.com/javase/1.5.0/docs/guide/language/generics.html | |||
[5] Venkat Subramaniam, ''Generics in Java – Part I'', from the AgileDeveloper Site : http://agiledeveloper.com/articles/GenericsInJavaPartI.pdf | |||
[7] Java Tutorials, Retrieved September 21st, 2010, from the Java Homepage: http://download.oracle.com/javase/tutorial/java/ | |||
[8] Using Java Reflection, Retrieved September 21st, 2010, from the Oracle Homepage: http://java.sun.com/developer/technicalArticles/ALT/Reflection/ | |||
[9] Java Annotations, Retrieved September 21st, 2010, from Javabeat Homepage: http://www.javabeat.net/articles/30-annotations-in-java-50-1.html | |||
[10] XDoclet: What is XDoclet, Retrieved September 21st, 2010, from the SourceForge Website: http://xdoclet.sourceforge.net/xdoclet/index.html | |||
[10] | |||
Latest revision as of 14:54, 13 October 2010
Metaprogramming in statically typed languages
What is Metaprogramming?
Metaprogramming is the technique that allows us to write programs that can manipulate other programs or themselves as a part of their data. Such programs help the programmer to avoid recompilations by executing their part of the work at compile time rather than at runtime.
The ability of a program to treat itself as a part of the data is known as reflection by virtue of which the program can modify its own structure and behavior. Often, metaprogramming and reflection are synonymous terms and one can be defined in the context of the other. Metalanguage is the language in which the metaprogram is written.
A most illustrative instance of metaprogramming is the use of Vectors in many languages, which are a set of multidimensional mathematical entities. Through metaprogramming, we can pass parameters to a generic class, the code for which will be generated by the compiler for each dimension of the Vector.
Example of Metaprogramming
The following figure applies the concept of Metaprogramming to the Ruby programming language
The attributes of the File entity are redefined and modified at runtime using the expressions of the programming language.
Now let us take another aspect of Metaprogramming in the same ruby language. Supposing we are having the following code in our ruby file.
COLORS = { :black => "000", :red => "f00", :green => "0f0", :yellow => "ff0", :blue => "00f", :magenta => "f0f", :cyan => "0ff", :white => "fff" }
The class can be defined as
class String
COLORS.each do |color,code|
define_method "in_#{color}" do "#{self}"
end
end
end
The above code generates new methods for the build in String class based on a list of colors and they wrap the particular String in the respective color by virtue of HTML tags.
In particular, we can use this code in our application as :
“ ’ Hello World’.in_blue”
which will print the text in blue color. This aspect of metaprogramming saves the programmer the tedious job of encoding each behavior in a type of method.
Metaprogramming in Java:
Metaprogramming in java comprises of three main components:
- Reflection
- Generics
- Annotations
Reflection in Java
The reflective nature of a Java program allows Java programs to introspect upon themselves and manipulate internal properties of the program. One tangible use of this feature is in JavaBeans in which a information about the classes are dynamically obtained via a Builder Tool as the classes are dynamically loaded. Reflection in Java is normally accomplished through the Reflection API which consists of the "Reflect" package and is available in the java.lang hierarchy.
Consider the following code
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } }
If it is invoked in the following manner
“java DumpMethods java.util.Stack”
The output will be:
public java.lang.Object java.util.Stack.push( java.lang.Object) public synchronized java.lang.Object java.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object)
The method names of java.util.Stack class are listed with their parameters and return types
- Class.forName : It is a static method of Class that loads the specific class which, in this case, is the java.util.Stack class
- getDeclaredMethods: It is another method of Class that retrieves the list of methods and return them as objects defined in the Stack class
- Method: Method is another class of which an array of objects is created to hold the values of the returned objects
Generics in Java
Generic programming is a type of computer programming in which the algorithms are written to accommodate data types whose values are to be specified late. Such data types are instantiated only when the particular datatype is passed as a parameter to the Generic class.
In Java, code is not created for each type specific instance of a Generic like other statically typed languages like C++. Bytecode is generated only once for each function and class and the generic types are replaced by “Object”, which is a built in generic type.
How Generics are defined?
Consider the use of the List class to define generics. Then, it can be defined as
List <WrapperClass type> object = new ArrayList <WrapperClass type>
Wrapper Class may be String or Integer or similar class types based on the requirement
An example of the use of Generics is as follows
import java.util.*; public class BoxingGenericsExample { public static void main(String args[]) { HashMap<String,Integer> hm = new HashMap<String,Integer>(); hm.put("speed", 20); } }
The HashMap can accommodate two values of String and Integer types which are declared using Generics
Generic Classes
It is possible to define classes in Generics
class GenericExample<T> { T ob; // declare an object of type T GenericExample(T o) //constructor initializing the object of T to the object passed as args { ob = o; } T getob() { return ob; } void showType() { System.out.println("Type of T is " + ob.getClass().getName()); } } public class GenDemo { public static void main(String args[]) { GenericExample<Integer> iOb= new GenericExample<Integer>(88); iOb.showType(); }}
At runtime the value of T will be the Integer class
Generic Interfaces and Methods
Similarly it is also possible to define interfaces and methods in Generics
public interface List<E> { void add(Ex); void display(); }
//Generic Method public static <T> void filter() { //Method code }
The main disadvantages of Generics are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code so runtime safety is compromised.
Annotations in Java
Annotations are syntactic metadata which can be added to the java source code and can include classes, methods, variables and packages. This is another manifestation of the reflective nature of Java in which such annotations may be embedded in class files and retrieved at runtime. An annotation definition might look like this
public @interface TestAnnotation { // Property Definition here. }
‘@’ indicates the start of an annotation definition. The above annotation is an interface level annotation. This is specified in the declaration of an annotation itself and is known as “Annotating an Annotation” The compiler has a reserved set of annotations for syntactic purposes among which three are worth mentioning
@Deprecated
The annotated element is deprecated and no longer in use.
//Example of a deprecated annotation @Deprecated static void deprecatedMethod() { //code }
@Override
The annotated element is meant to be overridden in the superclass
//Example of a override annotation @Override int overriddenMethod() { //code }
@SuppressWarnings
The compiler has to suppress warnings which it would otherwise generate. This is usually done when a deprecated method is used and warnings from the compiler are not desired.
//Example of a suppress warning annotation // compiler not to generate a warning @SuppressWarnings("deprecation") void useDeprecatedMethod() { objectOne.deprecatedMethod(); //deprecation warning - suppressed }
Technical issues: Meta Programming with JAVA
Every time a user wishes to write a Java Bean object, following key steps should be implemented. This includes:
- Making the class serializable
- Ensuring the class has a default constructor
- Writing getters and/or setters for all properties
- Writing methods to register and unregister listeners for the bound properties
Unit tests are seldom written for getters and setters and generally the process is error prone. These shortcomings are overcome by code generating tools like XDoclet and Eclipse but they have their own limitations.All these tools use their own template language and their functionality is restricted to the behaviour of C/C++ macros. In a metaprogramming language, the template and the code it generates are implemented in one language only. It is therefore possible to extend the language itself, by adding new constructs, rather than developing the object hierarchy.
How to resolve this problem?
Attribute oriented programming
It is a program-level marking technique to be exploited to enable meta programming and address the challenges posed by it. Programmers can mark elements like classes and methods to indicate that they maintain application-specific or domain-specific semantics. Application's business logic is separated from domain specific semantics using attributes. By keeping the implementation details of those semantics from program code hidden, attributes increase the level of abstraction and reduce programming complexity. This results in simpler and more readable programs. The program elements associated with attributes are transformed to more detailed programs by a supporting tool. A supporting tool can be a preprocessor.
XDoclet
Users can add more meaning to the code by adding meta data to the java source code in special JavaDoc tags. This technique, also referred as Attribute Oriented Programming, is made possible in Java by XDoclet, an open source code generation engine. XDoclet works by parsing the source file and generating several artifacts from it. Artifacts can include XML descriptors and/or source code. Using the information provided in the source code and in its JavaDoc tags, template generate these files. XDoclet includes a core module and constantly growing number of modules. Whenever there is a requirement for a new component, new modules can be written easily using this feature. XDoclet has several advantages that has made it an instant hit with the programming community. A few advantages are
- Redundancy elimination: Users need to write only the business logic and XDoclet generates the support code and “boiler-plate” for it.
- Extensibility: XDoclet is designed for modular programming. On identifying repeatable code, users can write XDoclet templates to generate the necessary code.
- Better understanding of J2EE programs: Users need to implement the enterprise bean and XDoclet generates the necessary interfaces, value objects, struts for the user.
XDoclet was initially conceived as tool for creating EJBs. Over the course of time, it has evolved into a code generation engine making programming a lot easier.
public class Matrix { /** @todo need to handle the case where there is no spoon */ public void reload() { // … }}
Now to use the XDoclet code we have to insert a todo tag in the Ant Build file like the following
<target name="todo" depends="init"> <documentdoclet destdir="todo"> <fileset dir="${dir.src}"> <include name="**/*.java" />
Prior to the release of the Metadata Facility, XDoclet was used for attribute oriented programming approach in Java.
Metadata Facility
An advanced and a sophisticated technique for Attribute Oriented Programming in Java is through the Metadata Facility (JSR-175) [14] which is included in the J2SE version 5.0. It is actually an API (Application Programming Interface) for enabling annotations of fields, methods and classes and thus enabling developement tools and runtime libraries to run them in a specific desired way.
References
[1] Lindegren, Patrik and Ostlund, Joakim, Metaprogramming in Java, C# and C++, 24th May, 2006
[2] Metaprogramming in Ruby, Retrieved September 21st , 2010, from Wikipedia page: http://en.wikipedia.org/wiki/Ruby_(programming_language)#Metaprogramming
[3] Attribute Oriented Programming, Retrieved September 21st, 2010, from the Wikipedia page :http://en.wikipedia.org/wiki/Attribute-Oriented_Programming
[4] Generics, Retrieved September 21st, 2010, from the Oracle Homepage:http://download.oracle.com/javase/1.5.0/docs/guide/language/generics.html
[5] Venkat Subramaniam, Generics in Java – Part I, from the AgileDeveloper Site : http://agiledeveloper.com/articles/GenericsInJavaPartI.pdf
[7] Java Tutorials, Retrieved September 21st, 2010, from the Java Homepage: http://download.oracle.com/javase/tutorial/java/
[8] Using Java Reflection, Retrieved September 21st, 2010, from the Oracle Homepage: http://java.sun.com/developer/technicalArticles/ALT/Reflection/
[9] Java Annotations, Retrieved September 21st, 2010, from Javabeat Homepage: http://www.javabeat.net/articles/30-annotations-in-java-50-1.html
[10] XDoclet: What is XDoclet, Retrieved September 21st, 2010, from the SourceForge Website: http://xdoclet.sourceforge.net/xdoclet/index.html