| Sign In/My Account | View Cart |
Quick and Easy Custom Templates with XDoclet
Pages: 1, 2
The last piece of the puzzle is how to put this all together and get our hands on the generated source file. This is where Ant comes in. We'll be doing three things:
On my development machine, I have the following directory structure:
trunk
|
+----+- src
+- xdoclet
|
+- build
+- src
+- com/mytest/account/controller
+- template
At first, this may seem a little confusing, with two src directories. However, I feel there is good reason for this, as I have a separate src directory under the xdoclet directory that allows me to keep separate all of the pseudocode and generated code. After I have run the Ant task, it's just a matter of copying the file over to the main src directory (on the same level of the trunk as the xdoclet directory) and adding in the implementation code. For the purpose of this article, I'm keeping these things separate from the source code base, which should prevent any build issues that might creep in if we try to integrate everything at once.
Based on the above directory structure, this is where our two files should live:
trunk/src/xdoclet/src/com/mytest/account/controller/TestController.java
trunk/src/xdoclet/template/MultiController.xdt
The .java file will need the package to match
the directory structure for XDoclet to be able to pick it up and run
the template against it. I found XDoclet only had the log4j
debugging levels set to INFO and so, when I did not
have the .java file in the correct tree, XDoclet would
not display any error messages; nor would it find and generate the
file. It wasn't until I went into the .jar and modified the
log4j.properties file so that debugging was turned on that
I got the proper debug messages saying there were no files to
process. Technically, this wasn't an error, but it kept me
scratching my head for some time, so be aware of this.
The following Ant task will use the above tree and place the generated code in the proper directory.
1. <!-- ========Xdoclet Target ======== -->
2.
3. <target name="xdoclet">
4.
5. <path id="xdoclet.classpath">
6. <fileset dir="${xdoc.home}/lib">
7. <include name="*.jar"/>
8. </fileset>
9. </path>
10.
11. <echo>+------------------------------------+</echo>
12. <echo>|Generating sources from xdoclet tree|</echo>
13. <echo>+------------------------------------+</echo>
14.
15. <taskdef name="doclet" \
classname="xdoclet.DocletTask" \
classpathref="xdoclet.classpath" />
16. <doclet destdir="${jxdoc.dir}/build"
17. verbose="true">
18. <fileset dir="${jxdoc.dir}/src">
19. <include name="**/*Controller.java" />
20. </fileset>
21. <template
22. templateFile="${jxdoc.dir}/template/MultiController.xdt"
23. destinationFile="{0}.java"
24. subTaskName="Create Controller file(s).." />
25. </doclet>
26.
27. </target>
A few settings will be required to run this.
xdoc.home should point to your XDoclet
install directory.You can run the task by issuing the following command: ant
xdoclet.
If all goes well, you should see the usual Ant BUILD
SUCCESSFUL message. Then, under the
xdoclet/build/com/mytest/account/controller directory,
your new file should appear, full of the necessary skeleton
properties and methods.
This template approach can also be adapted to generate not only
controllers, but beans, forms, services, etc. In the
xdoclet target, you would just have to add a new
taskdef for each object type you want to generate and provide a
different template. For example, if we want to generate service
objects, we could use the following taskdef:
1. <taskdef name="servicedoclet" \
classname="xdoclet.DocletTask" \
classpathref="xdoclet.classpath" />
2. <servicedoclet destdir="${jxdoc.dir}/build"
3. verbose="true">
4. <fileset dir="${jxdoc.dir}/src">
5. <include name="**/*Service.java" />
6. </fileset>
7. <template
8. templateFile="${jxdoc.dir}/template/Service.xdt"
9. destinationFile="{0}.java"
10. subTaskName="Create Service files(s).." />
11. </doclet>
Above, we see that we've changed the name of the taskdef to
servicedoclet and also the include fileset property
from *.Controller.java to *.Service.java,
which will only look for files ending in "Service.java."
On line 8, we are telling XDoclet to use the
Service.xdt template. So we see that it's fairly trivial to
add on special code generators once we have the initial setup
going. It is entirely possible (in fact, this is what I do) to
generate a few templates and, under the xdoclet task,
have it look through the source tree for each object type and
generate everything at once.
A word about Maven 2.0 and Archetypes: Maven 2.0 will contain a mechanism called Archetypes which allow for template-driven project code generation. While implemented differently--using Velocity for the templates--than what we have done above, it will basically accomplish the same things, but on a larger, project scale. I have tried Maven a few times and I can appreciate its scope. However, I feel it is much more a part of a larger picture and would require more developer effort and time (in the beginning, of course) to integrate than the example above. But it does address one of my initial issues, that I liked the fact that Rails worked with the developer on a project level. Maven, too, will operate on that project level, saving developers time by auto-generating the needed code based on set config parameters. This can only be a positive thing. For existing projects, however, the approach discussed here will probably be faster to implement and have less of a structural impact.
To recap, here's what we've accomplished:
This only scratches the surface of XDoclet templates. We've seen just one small, yet powerful, example of how templates can help you not just become a more efficient programmer, but also a smarter one. I hope it will save you as much time as it has me.
Field and ClassJason Lee has been developing web apps for the past ten years and currently is VP of technology at a small startup.
|
Related Reading Java Extreme Programming Cookbook |
Return to ONJava.com.
Showing messages 1 through 2 of 2.
It was quite easy.