http://www.developer.com/

Back to article

Code Smarter, Not Harder, With XDoclet


October 31, 2003

XDoclet is a template-driven development tool that allows developers to generate code, configuration files, or even documentation. This article will demonstrate how to download, install, configure, and use XDoclet to take the drudgery out of writing J2EE code.

Tools

To use XDoclet, you will need the following:

  • Java 2 Standard Edition SDK
  • Apache Ant 1.4.1 or later
  • XDoclet 1.1.2 or later

Downloading

To get XDoclet, go to http://sourceforge.net/projects/xdoclet/. The latest production release is version 1.1.2, but version 1.2.0 Beta 3 is also available. You will also need Apache Ant, v1.4.1 or later, which is available at http://ant.apache.org/. The Java 2 Standard Edition SDK is also required, and can be downloaded from http://java.sun.com/.

Installation

To install XDoclet, unzip the file to a directory of your choice. By default, this directory will be named XDoclet-version. You will also need to configure several environment variables. First, CLASSPATH must contain the tools.jar file found in the lib directory of the Java 2 SDK distribution. Your system path must contain the bin directory of the Java 2 SDK distribution, so that XDoclet can invoke the standard javadoc creation tool. Also, the J2EE_HOME environment variable should be set. You also need to install Ant, and set the ANT_HOME environment variable to the location of the Ant installation. The Ant tool's bin directory must be included in the system path.

The following subdirectories are found within the XDoclet-version directory:

  • docs—The documentation for the XDoclet template tags and source code. The template docs, which are very important for creating a code generation template, can be found in docs/templates. If you wish to extend XDoclet's capabilities, the API documentation is in docs/api.
  • lib—Contains the XDoclet.jar file.
  • samples—Contains sample source code that uses XDoclet's predefined EJB, JSP, and Web tags.
  • src—Contains the source code for XDoclet.

Doclet Tags

XDoclet uses doclet tags within JavaDoc comments to provide information that is used within templates to generate code, configuration files, or documentation. Below is an example of a doclet tag.

/**
* @jsp:attribute name="color" required="false"
*/

In the doclet tag above, the value jsp is the namespace of the doclet tag; attribute is the tag name, and the name-value pairs name="color" and required="false" are parameters.

The namespace groups tags with similar functions together. Some examples are the ejb namespace, which includes many tags for EJB generation, and the jsp namespace, which includes tags for creating custom JSP tag code and configuration files.

The tag identifies one particular function within the namespace. For example, the ejb:bean tag is used to provide data for generating EJB home, remote, and local interfaces, as well as EJB deployment descriptor files. Tags must be unique within a namespace, but may be duplicated in different namespaces.

Parameters supply information for the doclet tag to use within code generation templates. A parameter could be used as a simple placeholder, or could tell a template to conditionally generate code. For example, in the doclet tag shown above, the parameters could be used as values within the taglib.tld file for the JSP tag.

XDoclet Templates

XDoclet templates contain the logic that the XDoclet template engine uses to generate code. By convention, template files end with a .j extension. Many examples are included within the XDoclet source code.

Each template contains a mixture of source code and template tags. There are two types of template tag; block tags and content tags. Content tags produce some type of content based on the parameters supplied. For example, the tag <XdtMethod:methodTagValue tagName="jsp:attribute" paramName="name"/> would insert the value "color" from the doclet tag example above into the code being generated.

Block tags generally perform some logical function, such as iterating through a list of classes, methods, or packages, or optionally generating code based on the parameters supplied. The tag pair <XdtClass:forAllClasses> ... </XdtClass:forAllClasses> would iterate through all of the classes, and would generate code specific to each class upon each iteration.

Generating Code

Once you have created a template, you must include a step in your build.xml file so that Ant can generate the code. A sample is shown below.

<target name="generate-tagdoc">
<taskdef name="tagdoc" classname="XDoclet.DocletTask"
         classpath="${XDoclet.jar.path};${log4j.jar.path};
                    ${ant.jar.path}" />
<tagdoc sourcepath="${java.dir}" destdir="${tagdoc.dir}"
        classpathref="compile.classpath"
        excludedtags="@version,@author,@return,@exception" >
  <fileset dir="${java.dir}">
    <include name="**/*Tag.java" />
  </fileset>
  <template templateFile="${template.dir}/tagdoc.j"
            destinationfile="{0}.html"/>
</tagdoc>
</target>

This user-defined Ant task instructs XDoclet to process source code in the java.dir for all source code that ends in Tag.java. The template file tagdoc.j will be used to generate code based on the doclet tags found in the source code, with the exception of @author, @version, @return, and @exception, which are excluded from being processed. The generated code will be placed in the tagdoc.dir directory, and will have the same package structure and filename as the source file, as designated by the token {0} in the output filename, but the output will have an .html extension. A single output file could also be specified, but using the {0} token in the output filename implies that the template engine should generate one single file per source file that is processed.

Example Application

To demonstrate more fully how XDoclet templates can be used to generate code, we will examine a sample JSP tag application. Using XDoclet, we will generate a taglib.tld file for the custom tags within the application, a TagExtraInfo class for each tag, and HTML tag documentation for each tag. Luckily, XDoclet will do most of the work for us. The only source code that is manually written in the application is the code for the JSP tags themselves. Everything else, except for the demonstration index.jsp file, is derived using doclet tags, templates, and predefined XDoclet tasks in Ant.

Coding the Doclet Tags

Before any templates can be written, we must first document the code using doclet tags. Below is a sample SHOWING HOW TO USE DOCLET TAGS.

/**
* This JSP tag produces a greeting based on the parameters passed
* in.
* <ul>
* <li>formal - true|false If true, the greeting is
* "Greetings"; otherwise, it is "Hi"</li>
* <li>name - A non-empty string containing the name of the person
*            to be greeted</li>
* <li>times - An integer value from one to three that determines
*             how many greetings appear.  Default is one.
* </ul>
*
* @jsp:tag name="hello"
* tag-class="com.dlt.XDocletexamples.taglib.HelloTag.class"
* tei-class="com.dlt.XDocletexamples.taglib.HelloTagExtraInfo.class"
* body-content="empty"
*  description="This tag generates a formal or informal greeting
*               based on the parameters passed in."
*/
public class HelloTag extends TagSupport {
...
  /**
  Set the formal or informal greeting.
  * @param boolean formalGreeting If true, greeting is
  * "Greetings"; otherwise, "Hi"
  * @jsp:attribute name="formal" required="true" rtexprvalue="true"
  * type="boolean" description="If true, sets the greeting to
  * 'Greetings', otherwise, to 'Hi'."
  */
  public void setFormal(boolean formalGreeting) {
...
}
..
}

There are several things to note about this code listing. First, normal Javadoc procedures should be used. Adding doclet tags to your code will not affect Javadoc generation. Second, note the @jsp:tag doclet tag at the top of the listing. This is called a class tag because it only occurs at the class level, rather than occurring multiple times within a source file. Finally, note the @jsp:attribute and @jsp:attribute-validation doclet tags. These are method tags. They can appear on any method within the class that might be relevant to the code being generated. While the @jsp:attribute tag is a predefined doclet tag that can be processed by the XDoclet template engine, the @jsp:attribute-validation tag is a custom-defined tag created specifically for this application. To create your own doclet tags, simply define them in the source code and use them within a template, as we will see later.

Generating the Taglib.tld File

To generate the taglib.tld file required to use the custom JSP tags defined as part of the application, we will use an XDoclet task that is predefined for Ant. An example follows.

<target name="generate-tld" depends="prepare,resources">
          <taskdef
             name="webdoclet"
             classname="XDoclet.web.WebDocletTask"
          >
             <classpath refid="compile.classpath"/>
          </taskdef>

          <webdoclet destDir="${taglib.tld.dir}"
          sourcePath="${java.dir}"
          classpathref="compile.classpath"
               excludedtags="@version,@author"
               mergedir="${merge.dir}">
               <fileset dir="${java.dir}">
                  <include name="**/*Tag.java"/>
               </fileset>
          <jsptaglib xmlencoding="UTF-8"
          description="This taglib contains the greeting tags that
                       demonstrate how to use XDoclet to generate
                       code."/>
          </webdoclet>
</target>

When Ant executes this task, XDoclet will parse the source code in the java.dir directory, looking for @jsp:tag and @jsp:attribute tags. The taglib.tld file will contain the information specified in the parameter values for these tags. There is one interesting thing to note about this task. The mergedir= attribute specifies the location of a file called taglib-settings.xml, which contains information about the taglib version, JSP version, icons, and other information that will go into the taglib descriptor file. This merge file allows the deployment information to be kept separate from the build information, while still including the deployment information in the build process. Thus, a different taglib-settings.xml file could be used to specify information for test and production builds.

Besides the webdoclet task demonstrated above, Xdoclet contains many other predefined Ant tasks for generating code. For details on these tasks, and the doclet tags used during task processing, consult the Xdoclet documentation. Most notably, there are predefined tasks for EJB code generation, Struts code generation, and configuration file generation for many common application servers.

Generating the TagExtraInfo Classes

A TagExtraInfo class provides extra information about validating tag attributes to the JSP container at translation time. The template shown below validates strings whose length falls within a particular range, and integers whose value falls between a minimum and maximum value. Based on the doclet tags in the source code, XDoclet can generate a TagExtraInfo class for each tag class we create. Below is a partial listing of the template code found in the tei.j template file.

/**
 * Generated File - Do Not Edit!
 */

package <XDtPackage:packageOf><XDtClass:fullClassName/>
        </XDtPackage:packageOf>;

import javax.servlet.jsp.tagext.TagExtraInfo;
import javax.servlet.jsp.tagext.TagData;

public class <XDtClass:className/>ExtraInfo extends TagExtraInfo {
/**
* Validates the parameters sent to the JSP tag.
* @param TagData data The tag attributes passed to the JSP tag.
* @return true if all validation checks pass.
*/
public boolean isValid(TagData data) {
boolean valid = true;
<XDtMethod:forAllMethods>
<XDtMethod:ifHasMethodTag tagName="jsp:attribute">
<XDtMethod:ifHasMethodTag tagName="jsp:attribute-validation">
// Validate the <XDtMethod:methodTagValue
                 tagName="jsp:attribute"
                 paramName="name"/> tag attribute
if (valid && data.getAttribute("<XDtMethod:methodTagValue
                                 tagName="jsp:attribute"
                                 paramName="name"/>") != null) {

<XDtMethod:ifMethodTagValueEquals tagName="jsp:attribute"
                                  paramName="type"
                                  value="java.lang.String">
String value = (String)data.getAttribute("<XDtMethod:methodTagValue
                                           tagName="jsp:attribute"
                                           paramName="name"/>");
valid = isValidString(value, <XDtMethod:methodTagValue
                              tagName="jsp:attribute-validation"
                              paramName="minLength"/>,
                             <XDtMethod:methodTagValue
                              tagName="jsp:attribute-validation"
                              paramName="maxLength"/>);
</XDtMethod:ifMethodTagValueEquals>
<XDtMethod:ifMethodTagValueEquals tagName="jsp:attribute"
                                  paramName="type" value="int">
Integer value = (Integer)data.getAttribute(
                "<XDtMethod:methodTagValue
                  tagName="jsp:attribute" paramName="name"/>");
valid = isValidInt(value.intValue(),
        <XDtMethod:methodTagValue
         tagName="jsp:attribute-validation"
         paramName="minValue"/>,
        <XDtMethod:methodTagValue
         tagName="jsp:attribute-validation" paramName="maxValue"/>);
</XDtMethod:ifMethodTagValueEquals>
} // if
</XDtMethod:ifHasMethodTag>
</XDtMethod:ifHasMethodTag>

</XDtMethod:forAllMethods>
return valid;
} // isValid()

private boolean isValidString(String value, int minLength,
                              int maxLength) {
...
} // isValidString()

private boolean isValidInt(int value, int minValue, int maxValue) {
...
} // isIntegerValid()
} //  <XDtClass:className/>ExtraInfo

The template consists of XDoclet template tags and Java code. Within this template, everything that is not enclosed within <XDtxxx> and </XDtxxx> tags will appear in the generated source code as-is. When the template engine encounters a content template tag, it will fill in the content referenced within the tag. For the <XdtClass:className> tag, the content returned by the template tag will be the name of the current class being processed by the template engine. Thus, <XDtClass:className/>ExtraInfo becomes HelloTagExtraInfo when the HelloTag source file is processed, and GoodbyeTagExtraInfo for the GoodbyeTag class.

Many content tags, such as the <Xdtpackage:packageOf> tag shown at the top of the listing, provide information that is obtained through introspection of the class files being processed. In the case of the <XdtPackage:packageOf> tag, the tag processes the fully qualified class name passed into the tag to obtain the same package name as the class being processed. Information about packages, classes, method signatures, and almost anything that can be learned through introspection, can be obtained by using an Xdoclet template tag.

For the block tags, the result of the processing depends on the function of the tag. For example, the <XdtMethod:forAllMethods> tag will iterate through all methods within the current class. This is useful because the <XdtMethod:methodTagValue> template tag can then be used to extract the parameter values from each method with a @jsp:attribute tag, for example, to be used within the template.

In the case of the <XdtMethod:ifHasMethodTag> template tag, the code within the opening and closing template tag is only generated if a doclet tag matching the specified tag name and parameter name is found for the current method. Thus, methods without the tag are skipped during processing. Likewise, template tags are available that would only generate code if a method doesn't have a particular doclet tag.

Generating the Tag Documentation

To demonstrate one of the potential uses for XDoclet beyond Java code generation and creation of XML configuration files, we will generate tag documentation for each custom JSP tag within the application. For each tag, a template is used to generate that tag's documentation, and a table of contents for the entire tag library is also generated. Because we have already looked at most of the template tags used in the tagdoc.j template file in the earlier template discussion, we will not discuss it here. However, the tagdoc_toc.j template, shown below, has one interesting feature. A listing of the tagdoc_toc.j template is shown below.

<html>
<head>
<title>Taglib Index</title>
</head>
<body>
<p>
<table width="100%">
<XDtClass:forAllClasses>
<XDtClass:ifHasClassTag tagName="jsp:tag">
<td align="left" valign="top" width="100%">
<a href="<XDtPackage:packageNameAsPath/>/
         <XDtClass:className/>.html"><XDtClass:className/></a>
</td>
</XDtClass:ifHasClassTag>
</XDtClass:forAllClasses>
</table>
</p>
</body>
</html>

The table of contents is a simple table containing hyperlinks to all of the individual tag documentation files. Unlike the TagExtraInfo template, this template only generates one output file for all of the source files being processed. The <XdtClass:forAllClasses> tag iterates through all of the source files specified in the <fileset> tag of the Ant task that invokes the template. Also, the <XDtClass:ifHasClassTag tagName="jsp:tag"> tag processes the class tags at the top of each class file, generating a table entry only for those classes with a @jsp:tag doclet tag at the class level.

Building the Application

To try XDoclet for yourself, download the sample application here and unzip it within the webapps directory of your servlet container. The application contains the following directories within the XDoclet-examples/web-inf directory.

  • classes—Destination for all compiled Java classes
  • doc—Javadocs directory for source code
  • lib—Jar files directory
  • src/java—The Java source code
  • src/merge—The location of the taglib-settings.xml merge file mentioned earlier
  • src/Templates—The location of the *.j template files
  • src/build.xml—The Ant build file for this application

To build the project, change to the XDoclet-examples/web-inf/src directory and run Ant. You will see the three steps of XDoclet code generation executing. After the code is generated, all of the code, both generated and manually created, will be compiled to the classes directory.

After the project is built successfully, check out the generated code.

  • taglib.tld—Generated taglib descriptor
  • src/generated—Generated TagExtraInfo classes
  • tagdocs—Tag documentation

Testing the Code

To test the application, and see that the generated code actually works, start your servlet container and click on http://localhost:8080/XDoclet-examples/index.jsp. You will see the output from the <hello> and <goodbye> tags displayed. If you are using a servlet container other than Tomcat, consult the documentation for your servlet container regarding deployment of the XDoclet-examples.war file created during the build process. The URL or port for the test link above may also be different.

Extending XDoclet

Although XDoclet comes with a rich library of template tags, it is possible to extend XDoclet by creating your own template tags. To do so, you will need to extend the XDoclet.template.TemplateTagHandler class.

It might also prove useful to create your own custom Ant tasks, rather than using the <taskdef> tag to define a task each time one is needed. The <webdoclet> tag is an example of this approach. To create your own task, you will need to extend XDoclet.DocletTask, and perhaps XDoclet.DocletSubTask, if the task will require multiple steps.

Consult the XDoclet API documentation for more information on using these classes.

Conclusion

XDoclet is a powerful code generation tool. With the large amount of grunt work required to code EJBs and J2EE configuration files, XDoclet is a great way to save time and effort. In this article, you have seen how to generate descriptor files, code, and HTML from doclet tags. The code you can generate is limited only by your imagination.

Resources

XDoclet download: http://sourceforge.net/projects/xdoclet/

Sample Application: xdoclet-examples.zip

Ant Download: http://ant.apache.org/

J2SDK Download: http://java.sun.com/

About the Author

David Thurmond is a Sun Certified Developer with over eleven years of software development experience. He has worked in the agriculture, construction equipment, financial, and home improvement industries.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date