From: http://www.javaresearch.org/article/showarticle.jsp? Column = 331 & Thread = 26106
XDoclet
XDoclet is a code generation tool that can free you from the heavy repetitive work during Java development. XDoclet allows you to develop your application system more quickly, and you only need to pay less effort than before. You can hand over the lengthy and necessary code at hand to help you complete it. You can escape the "deployment descriptor hell" and make your application system easier to manage. All you have to do is add some javadoc attributes in your comments. Then, you will be surprised at what XDoclet does to do.
When talking about XDoclet, it is easy to get confused, that is, XDoclet is not only a system code generation application, but also a code generation framework. Although the details of each application system are ever-changing (for example, EJB code generation is different from struts code generation, and JMX code generation is another scene ), however, the core concepts and usage of these code generation are similar.
In this chapter, we will see the basic concepts of the XDoclet framework that penetrate into all XDoclet code generation programs. But before that, let's start with an example.
2.1 XDoclet in action
Every programmer will realize that their program will never be completed. There will always be some other functions to be added, some bugs to be fixed, or you need to constantly refactor them. Therefore, it is a consensus to add comments in the code to remind yourself (or other programmers) of the tasks to be completed.
How can we track whether these tasks have been completed? Ideally, you will collect and sort out a todo task list. In this regard, XDoclet provides a powerful todo generator to help you complete this task. This is a good opportunity to introduce XDoclet into the project.
2.1.1 a public task
Suppose you are developing a class that uses a spoon.
Public class Matrix {
// Todo? Handle cases where no spoon exists
Public void reload (){
//...
Spoon spoon = getspoon ();
//...
}
}
Ideally, the next time you read this code, you will handle the "null spoon" issue. But if you come back to read this code after a long time, do you still remember to have some work to do in this class? Of course, you can search for todo globally in your source code, or even have a built-in todo list in your integrated development environment. However, if you want to mark the class and method of the task, XDoclet can be another option. XDoclet can generate a todo report for your project.
2.1.2 add an XDoclet tag
To convert your todo project into another more formal format, you need to make some minor changes to the Code. As follows:
Public class Matrix {
/** @ Todo: when no spoon is available */
Public void reload (){
//...
}
}
Here, a javadoc tag of the class required by XDoclet is added. XDoclet generates a todo report by using the tag information and the class and method of the tag in this case.
2.1.3 integration with ant
To generate a todo report, make sure that XDoclet is correctly installed on your machine.
In an ant task, at least one target (such as the init target) Definition <documentdoclet> task must be included. This is an ant custom task, for example:
<Taskdef name = "documentdoclet"
Classname=”xdoclet.modules.doc. documentdoclettask"
Classname = "XDoclet. Lib. Path"/>
This <documentdoclet> task is one of the XDoclet core code generation applications.
Now, you can add a todo target to the ant build file to call this task to generate the todo report, for example:
<Target name = "Todo" depends = "init">
<Documentdoclet destdir = "Todo">
<Fileset dir = "$ {dir. SRC}">
<Include name = "**/*. Java"/>
</Fileset>
<Info/>
</Documentdoclet>
</Target>
<Info> the subtask traverses your source file, finds the todo tag, and generates a todo report in HTML format under the todo subdirectory.
2.1.4 create a more professional todo report
The todo report generated by XDoclet can have a more professional appearance. The report will list an overview of which package contains the todo items (and the number of Todo items ). Todo items can be clearly different from methods, classes, and fields in reports. Class-level todo items are marked with class, and method-level todo items are marked with m on the method signature. The todo items related to the constructor and the domain are also marked similarly.
This task looks simple, but considering that all you need to do is add some formatted @ todo tags to the annotations, which are loose annotations that only people can understand, this label is machine readable and easier to program. The generated output is easier to read and more commercialized.
2.2 tasks and subtasks
Generating todo reports is only the tip of the iceberg that XDoclet can accomplish. At the beginning, XDoclet became famous because it could automatically generate complicated EJB interfaces and deployment description files. However, XDoclet has developed into a fully functional and Attribute-oriented code generation framework. J2EE code generation is only an application of XDoclet, and the tasks it can accomplish far surpass the generation of J2EE and project documents.
2.2.1 XDoclet task
So far, we have been discussing how to use XDoclet to generate code. But in fact, we should say that we use a specific task of XDoclet to generate code, such as <ejbdoclet>. Each XDoclet task focuses on a specific field and provides a wide range of code generation tools in this field.
[Definition: task is a high-level concept for generating applications using code in XDoclet.]
In XDoclet, there are currently seven core tasks as shown below.
<Ejbdoclet>: generates EJB, tool class, and deployment descriptor for the EJB domain.
<Webdoclet>: for web development, generate Serlvet, custom tag library, and Web framework files.
<Hibernatedoclet>: Hibernate Persistence, configuration file, mbeans
<Jdodoclet>: JDO, metadata, Vender Configuration
<Jmxdoclet>: JMX, mbean interface, mlets, and configuration file.
<Doclet>: Use a custom template to generate code.
<Documentdoclet>: generate a project file (for example, a todo column Report)
Among them, <ejbdoclet> is the most commonly used, and many projects only use XDoclet for EJB code generation. <Webdoclet> is followed by a common code generation task. Of course, it is possible to use several XDoclet tasks simultaneously in a project (and also recommended), but these tasks are completely independent, they cannot communicate with each other directly.
2.2.2 XDoclet subtask
XDoclet tasks are related to fields. XDoclet tasks in a specific field are composed of many closely coupled subtasks, each of these subtasks only executes a very specific and simple code generation task.
[Definition: subtasks are the code generation process of a single object provided by a task.]
A task provides the context for executing a subtask and manages the associated subtask organizations. The task depends on these subtasks to generate code. It is very common to call multiple subtasks in a task to complete a variety of large-scale code generation tasks. For example, when developing EJB, you may want to generate a home interface, a remote interface, and a ejb-jar.xml descriptor file for each bean. This is three independent code generation subtasks in the context of the <ejbdoclet> task.
Sub-tasks can be arranged in combination to meet the needs of project code generation. The sub-tasks contained in an XDoclet task often share functions and use the same XDoclet tag in the source file. This means that when you start a task, you can easily integrate it into a related sub-task without great changes.
Subtask Interaction
Let's take the <ejbdoclet> task as an example to see how the associated subtasks are associated. Suppose you are developing a CMP (container management persistence) Entity Bean. You want to use some <ejbdoclet> subtasks:
• <Deploymentdescriptor>: generate the ejb-jar.xml deployment descriptor file.
• <Localhomeinterface>: generate the local home interface.
• <Localinterface>: generate the local interface.
When executing the preceding sub-tasks, you need to mark the CMP domain of your object bean. When you publish your bean, you also need to provide the ing between specific tables and columns in a specific relational database and your CMP Entity Bean in the developer-related deployment descriptor. XDoclet allows you to add some link ing attributes based on the existing CMP XDoclet attributes. Then, you can add a developer-related sub-task (such as <JBoss> or <WebLogic>) to the task to generate the deployment descriptor file. XDoclet provides support for almost all application servers. You only need some minor initialization changes to generate code related to these application servers.
But that's just the tip of the iceberg. You can also use the <entitycmp> subtask to generate an implementation subclass of the object bean interface for your bean. If you use the <valueobject> subtask to generate a value object for your bean, the <entityemp> subtask will also generate the implementation code of the method for your value object.
I think it's incredible. Unfortunately, XDoclet does not provide the <cupofcoffee> subtask. Otherwise, we can have a cup of coffee and have a rest.
This document does not describe all the sub-tasks of <ejbdoclet> or all the code generation functions that can be completed by <ejbdoclet>, I just want to show you how tasks work together. Once you start and get familiar with an XDoclet subtask, it will be very easy to get familiar with another subtask-that is, every subtask is isolated, using this subtask that can work with each other, the development cost will be significantly reduced, and the effect will be more immediate.
2.3 use ant to execute tasks
XDoclet "married" to ant. XDoclet is a custom task of ant. In addition, there are no other methods to run XDoclet tasks. Fortunately, ant has become the de facto standard for Java build tools, so this is not a limit. In fact, this close relationship between XDoclet and ant allows XDoclet to participate in any ant build process.
2.3.1 declare a task
XDoclet is not released with ant, so if you want to use XDoclet, You need to download and install it separately. Before using any XDoclet task, you must declare it using ant's <taskdef> task. For example:
<Taskdef name = "ejbdoclet"
Classname = "XDoclet. modules. EJB. ejbdoclettask"
Classpathref = "XDoclet. Lib. Path"/>
If you are familiar with ant, you will know that this code tells ant to load the task definition of <ejbdoclet>. Of course, you can also name this custom task in any way you like, but it is best to follow the standard naming rules to avoid confusion. The classname and classpathref attributes tell ant where to find the XDoclet class that implements this custom task. If you want to use other XDoclet tasks, you must declare them first.
The common practice is to put all the XDoclet tasks that need to be used in one of ant's targets, so that if you need to use these tasks in other targets, you only need to depends this task. You may have included the init target in the ant build file, which is a good place to place the XDoclet task Declaration (if you do not have one, you can also create one ). The following example adds the declaration of <ejbdoclet> and <webdoclet> to an init target:
<Target name = "init">
<Taskdef name = "documentdoclet"
Classname=”xdoclet.modules.doc. documentdoclettask"
Classpathref = "XDoclet. Lib. Path"/>
<Taskdef name = "ejbdoclet"
Classname = "XDoclet. modules. EJB. ejbdoclettask"
Classpathref = "XDoclet. Lib. Path"/>
<Taskdef name = "webdoclet"
Classname = "XDoclet. modules. Web. webdoclettask"
Classpathref = "XDoclet. Lib. Path"/>
</Target>
Now, the task has been declared. XDoclet is "ready for release ".
2.3.2 use a task
You can use declared tasks in any target. In the context of a task, you can call related subtasks. Let's take an example. This example calls the <ejbdoclet> task. Don't worry about not understanding the syntax details. Now you only need to care about some basic concepts.
<Target name = "generateejb" depends = "init">
<Ejbdoclet destdir = "$ {gen. SRC. dir}">
<Fileset dir = "$ {SRC. dir}">
<Include name = "**/* bean. Java"/>
</Fileset>
<Deploymentdescriptor destdir = "$ {EJB. Deployment. dir}"/>
<Homeinterface/>
<Remoteinterface/>
<Localinterface/>
<Localhomeinterface/>
</Ejbdoclet>
</Target>
Think of a task as a configuration environment required by the sub-program. (Remember, the sub-task is actually used for code generation ). When a subtask is called, The subtask inherits the context from the task. Of course, you can overwrite these values as needed. In the preceding example, because the deployment descriptor file generated by the <deploymentdescriptor> subtask and the Java source files generated by the subtasks that generate various interfaces need to be placed in different locations, therefore, the destdir attribute value is overwritten. Deploy the descriptor file to a place that can be easily included when packaging the ejb jar file, and the generated Java code should be placed in a place where the Java compiler can be called for compilation. These subtasks need to be closely related, but as long as you need them, you can have sufficient autonomy to control the task generation environment.
The <fileset> attribute is also applied to all subtasks. This is a complex type of ant (simple type relative to text and numeric values), so it is declared in the task as a child element. Do not confuse it with subtasks. Of course, if you want to specify a different input file set in a subtask, you can also place a <fileset> sub-element in this subtask to overwrite it.
The configurable options of subtasks are far more than that. In the next chapter, we will continue to introduce all tasks, subtasks, and common configuration options.
2.4 mark your code with attributes
Reusable code generation systems need input to generate output of interest. A Parser Generator also needs a language description to parse and generate a parser. A business object code generator requires a domain model to know which business objects to generate. XDoclet requires the Java source file as the output to generate related classes or deployment/configuration files.
However, the source file may not provide all the information required for code generation. Consider a servlet-based application. When you want to generate a web. xml file, the Servlet Source file can only provide the class name and the appropriate servlet interface method. Other information, such as Uri pattern ing and initialization parameters required by Servlet, is not covered. Obviously, if the class does not provide you with this information, you need to manually enter this information in the web. xml file.
XDoclet certainly does not know this information. Fortunately, the solution is simple. If the required information is not provided in the source file, it is provided by adding some XDoclet attributes to the source file. XDoclet parses the source file, extracts these attributes, and passes them to the template. The template uses the information to generate code.
2.4.1 profiling attributes
The XDoclet attribute is actually an extension of javadoc. They have the same attributes as javadoc in appearance and use and can be placed in javadoc document annotations. The document comment starts with/** and ends. The following is a simple example:
/**
* This is a javadoc annotation.
* Annotations can be divided into multiple rows, each row starts with a star number.
*/
All texts in the annotations are considered as javadoc annotations and can be accessed by XDoclet. Annotation blocks are generally related to an object in the Java source file and follow the object. Comments without following the entity will not be processed. Classes (or interfaces) can have annotation blocks, methods and fields can also have their own annotation blocks, such:
/**
* Class comment Block
*/
Public class someclass {
/** Domain comment block */
Private int ID;
/**
* Constructor comment Block
*/
Public someclass (){
//...
}
/**
* Method comment Block
*/
Public int GETID (){
Return ID;
}
}
The comment block is divided into two parts: the description part and the label part. When the first javadoc tag is encountered, the tag section starts. The javadoc tag is also divided into two parts: Tag Name and tag description. The label description is optional and can be multiple rows. For example:
/**
* This is the description section.
* @ Tag1 the label part starts from here.
* @ Tag2
* @ Tag3 there is no label description for the previous tag.
* This label has multiple line label descriptions.
*/
XDoclet extends the javadoc tag using parameterized labels. In XDoclet, you can add the name = "value" parameter to the label description of the javadoc tag. This tiny change greatly enhances the expression capability of the javadoc tag, so that the javadoc tag can be used to describe complex metadata. The following code describes the object bean method using the XDoclet attribute:
/**
* @ EJB. Interface-Method
* @ EJB. Relation
* Name = "blog-entries"
* Role-name = "blog-has-entries"
* @ EJB. Value-Object
* Compose = "com. xdocletbook. Blog. value. entryvalue"
* Compose-name = "entry"
* Members = "com. xdocletbook. Blog. Interfaces. entrylocal"
* Members-name = "entries"
* Relation = "external"
* Type = "java. util. Set"
*/
Public abstract set getentries ();
Parameterized tags allow logical association of attributes in a combination. You can add metadata describing this class so that the class information is sufficient to generate code. In addition, programmers can quickly understand how this class is used by reading such meta information. (If you do not understand the metadata in this example, do not worry. In chapter 4th, we will learn the EJB-related labels and their meanings .)
In addition, note that in the preceding example, all tag names start with EJB. XDoclet uses namespace. tagname to provide a namespace for a tag. In addition to javadoc, you can also organize task-related labels to avoid confusion between tasks.
2.5 code generation mode
XDoclet is a template-based code generation engine. From the high-level view, the output file is actually generated by parsing and executing various templates. If you understand the template and the context environment it executes, You can precisely understand what XDoclet can generate and what it cannot generate. If you are evaluating the XDoclet platform, understanding these concepts is very important. Otherwise, you may miss many of the powerful functions of XDoclet, and may be confused by some limitations of XDoclet.
XDoclet runs in the ant Build File environment. It provides ant custom tasks and subtasks to interact with the XDoclet engine. A task is a sub-task container that executes code generation. Subtask call template. The template provides a cookie model for generating code. XDoclet parses the input source file, extracts the XDoclet attribute metadata from the source file, and then provides the data to the template to drive the template execution. In addition, the template also provides merge points, allowing you to insert some template fragments (merged file Merge files) to customize code generation as needed.
2.5.1 template Basics
XDoclet uses a code template to generate code. Template is the prototype of the file you want to generate. The template uses XML tags to guide the template engine to adjust Code Generation Based on Input classes and their metadata.
[Definition: A template is an abstract mode view that generates code or description files. When the template is parsed, the specified details are filled in.]
A template usually has an execution environment. The template may be applied in a class environment (convert to generate transform generation), or in a global environment (aggregate to generate aggregate generation ). Conversion generation and aggregation generation are two types of XDoclet task modes. Understanding the differences between them is very important for understanding XDoclet.
When you use XDoclet to generate the layout descriptor file, you use aggregate generation. The descriptor file arrangement is not only related to one class, but also needs to aggregate information from multiple classes to one input file. In this generation mode, parsing a template will only generate one output file, no matter how many input files are there.
In the conversion generation mode, the template parses each source file once and generates the output according to the context of the file class. In this mode, an output file is generated for each input file.
A good example of converting the generation mode is to generate the local and remote interfaces of EJB. Obviously, interfaces are one-to-one related to bean classes. Extract information from each class (class and its methods, fields, interfaces, and XDoclet attributes) and convert it to an interface. No additional information is required.
The extracted interface from the implementation seems a bit backward. If you write a program by hand, an interface will be defined first, and then a class will be written to close it. But XDoclet cannot do it. XDoclet cannot help you implement an existing interface because it cannot help you generate your business logic. Of course, if the business logic can be obtained from the interface itself (such as the get/set accessors of JavaBean) or declared using the XDoclet attribute, it is not impossible to generate the business logic code to implement an interface. But in general, this is not realistic. In comparison, it is much easier to provide an implementation and describe the association between the interface and the implementation.
The main difference between aggregation generation and conversion generation is their environment information. Even if a code generation task generates a Java file, it is generally not commonly used for aggregation generation, it is impossible to generate a Java class because it also requires some important information such as the package of the class and the class name you want to generate. If clustering is required, the configuration information must be provided separately.
2.5.2 template tag
We have a deep understanding of the template before we can see what it looks like. What does the template look like? It is a bit like a JSP file. They all contain files and XML tags. When an output file is generated, the XML tag is parsed, and the text is generated and displayed at the location of the XML tag. In addition to the XML tag headers with xdt as the namespace, the XML tag will be parsed by the XDoclet engine, and the other XML tag XDoclet will be ignored. The following code snippet shows the "classic shape" of the XDoclet template ":
Public class
<Xdtclass: classof> <xdtejbfacade: remotefacadeclass/> </xdtclass: classof>
Extends observabe {
Static <xdtclass: classof> <xdtejbfacade: remotefacadeclass/> </xdtclass: classof>
_ Instance = NULL;
Public static <xdtclass: classof> <xdtejbfacade: remotefacadeclass/> </xdtclassof>
Getinstance (){
If (_ instance = NULL ){
_ Instance =
New <xdtclass: classof> <xdtejbfacade: remotefacadeclass/>
</Xdtclass: classof> ();
}
Return _ instance;
}
}
After studying this template, you will find that it generates a class definition. This class defines a static variable instance and uses a static method to control access to this static file. With the help of Java syntax, you can easily infer that the directories of the XDoclet template labels are generated class names, although you are not very familiar with how the labels work.
Even if you have never planned to write a template by yourself, it is necessary to understand how the template is parsed and run. Sooner or later, you will call a failed XDoclet task without generating the expected output. The quickest way to find out the cause is to directly check the template file, let's see what went wrong.
Let's take a look at the piece that generates the static domain definition:
Static <xdtclass: classof> <xdtejbfacade: remotefacadeclass/> </xdtclass: classof>
_ Instance = NULL;
In the eyes of XDoclet, this template code is very simple, that is:
Static <tag/> _ instance = NULL;
XDoclet parses and executes labels. If there is output, the input is returned to the text. Some labels perform some operations to store the output in a stream. Such tags are called content tags because they generate content.
Another type of tag is called the body tag. The Body Tag contains text between the start and end tags. Body labels are powerful. In these texts, they can also be a piece of template that can be parsed by peripheral labels. For example, in the preceding example, the xdtclass: classof tag contains the template snippet:
<Xdtejbfacade: remotefacadeclass/>
The classof tag parses this template, extracts the restricted content, and removes the front package. Only the class name is output. The body tag does not always parse its content. Before doing this, they will check some external judgment conditions in advance (for example, checking whether you are generating an interface or a class ). Here, the label is called the conditional label ). Some body labels provide similar iteration functions, and their content will be parsed multiple times. For example, a tag parses the content once for every method in the class.
XDoclet labels provide many high-level code generation functions, but sometimes they may not be flexible enough or their presentation capabilities cannot meet your needs. At this time, you can choose to expand the XDoclet template engine compared to developing another set of general function template engines. You can use a Java platform with more expressive and powerful functions to develop your own set of labels.
2.6 Use merging Customization
The main reason why code generation systems are rarely used is that they can only generate rigid and inflexible code. Most code generation systems do not allow you to modify the code they generate. if the system is not flexible enough, the best extension you can do is to inherit the code generated by the extension, or use some common design patterns (such as proxy and Adaptor) to meet your needs. In either case, this is not a good way to generate the code you want to generate. It is best for a code generator to generate wygiwyg (what you generate is what you get) to replace the code that does not meet your requirements. Therefore, flexible customization is a prerequisite for generating code that fully meets requirements.
XDoclet supports customization through merge points ?? The merge point is the place where custom code can be inserted during runtime in the template file definition. Sometimes, merging points can even affect the generation of global code, not only allowing you to add custom content, but also fundamentally changing what will be generated.
[Definition: Merge points is a predefined extension of the template that allows you to add custom content during code generation.]
Let's look at the template code extracted from the XDoclet source code. At the end of the template that generates a primary key for the object bean, this merge point is defined:
<Xdtmerge: Merge file = "entitypk-custom.xdt"> </xdtmerge: Merge>
If you create a file named entitypk-custom.xdt under your merge directory, the contents of this template file will be included in this merge point. You can customize and execute all the powerful functions that can be executed by high-level templates, and perform operations that can be performed by all templates (including defining custom tags and their own merge points ).
The preceding merge points use the same file for all class environments. Of course, you can also use different merged files for each class environment. This is useful if you do not want to customize all class files, or you do not want to rewrite the template for some changes. Regardless of the motivation, the merging points of classes are easily identified: they will include an XDoclet class-by-class mark {0} in their names }. Here is an example of generating the security role reference in the ejb-jar.xml file:
<Xdtmerge: Merge file = "EJB-sec-rolerefs-{0}. xml">
<Xdtclass: forallclasstags tagname = "EJB: Security-role-Ref">
<Security-role-ref>
<Role-Name>
<Xdtclass: classtagvalue
Tagname = "EJB: Security-roleref"
Paramname = "role-Name"/>
</Role-Name>
<Role-link>
<Xdtclass: classtagvalue
Tagname = "EJB: Security-roleref"
Paramname = "role-link"/>
</Role-link>
</Security-role-ref>
</Xdtclass: forallclasstags>
</Xdtmerge: Merge>
This template traverses all beans in the project. For each bean, XDoclet extracts the bean name from the bean file name, replaces {0}, and searches for the merged File Based on the replaced file name. For example, if you have a bean named blogfacadebean, XDoclet will try to find a merge file named ejb-src-rolerefs-BlogFacade.xml.
If the merged file cannot be found, the content template of the <merge> label will be parsed. This means that the merging point can not only provide customized content, but also define a replacement point in a template file. When the custom content does not exist, use the content in the replacement point. Not all XDoclet tasks provide merging points with replacement content. Generally, they prefer to provide only one simple merging point, parse and import the contents of the merged file only when the merged file exists. This depends on which merge point the task developer thinks is more in line with his/her requirements.
What's more, we haven't introduced how to locate the merged file in XDoclet. Each XDoclet task or subtask provides a mergedir attribute, which is used to set the directory where you store the merged file.