﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-XZC.Log-随笔分类-Xdoclet</title><link>http://www.blogjava.net/xzclog/category/16885.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:24:54 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:24:54 GMT</pubDate><ttl>60</ttl><item><title>read-AppFuse-16-XDoclet学习续</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79160.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 01:00:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79160.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79160.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79160.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79160.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79160.html</trackback:ping><description><![CDATA[● xdoclet学习续<br />　　Xdoclet是一个代码自动生成的工具<br />　　XDoclet任务就是Ant的自定义任务，除此以外，没有其他运行XDoclet任务的方法。<br />　　XDoclet它有两个重要的组件：<br />　　进行特殊标记的 Java 源文件。 <br />　　预先定义的模板。[引用]<br />　　 <br />　　 <br />　　Merge File用来处理无法在Source Code中加xdoclet tag的情况。<br />　　 <br />　　Ø XDoclet中的核心任务：<br />　　&lt;ejbdoclet&gt;：面向EJB领域，生成EJB、工具类和布署描述符。<br />　　&lt;webdoclet&gt;：面向Web开发，生成serlvet、自定义标签库和web框架文件。<br />　　&lt;hibernatedoclet&gt;：Hibernate持续，配置文件、Mbeans<br />　　&lt;jdodoclet&gt;：JDO，元数据，vender configuration<br />　　&lt;jmxdoclet&gt;：JMX，MBean接口，mlets，配置文件。<br />　　&lt;doclet&gt;：使用用户自定义模板来生成代码。<br />　　&lt;documentdoclet&gt;：生成项目文件（例如todo列报表）<br />　　 <br />　　Ø webdoclet sub task<br />　　XDoclet并没有和Ant一起发布，所以如果你想要使用XDoclet的话，就需要单独的下载和<br />　　安装。在使用任何一个XDoclet的任务之前，你首先需要在使用Ant的&lt;taskdef&gt;任务来声<br />　　明它。<br />　　&lt;deploymentdescriptor&gt;：产生标准的web引用配置文件web.xml，destdir属性设定<br />　　web.xml文件的存放位置。<br />　　XDoclet通过合并点(merge points)支持定制,合并点是在模板文件定义里允许运行时插入定制代码的地方,使用mergedir属性设置。<br />　　 &lt;target name="webdoclet" depends="compile-web" <br />　　 unless="webdoclet.unnecessary"<br />　　 description="Generate web and Struts descriptors"&gt;<br />　　 &lt;taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask"&gt;<br />　　 &lt;classpath&gt;<br />　　 &lt;path refid="xdoclet.classpath"/&gt;<br />　　 &lt;path refid="web.compile.classpath"/&gt;<br />　　 &lt;/classpath&gt;<br />　　 &lt;/taskdef&gt;<br />　　 &lt;!—mergedir完成模板文件合并的功能--&gt;<br />　　 &lt;webdoclet destdir="${webapp.target}/WEB-INF"<br />　　 force="${xdoclet.force}"<br />　　 mergedir="metadata/web"<br />　　 excludedtags="@version,@author"<br />　　 verbose="true"&gt;<br />　　 &lt;!—找出目录src/web 和${build.dir}/web/gen文件中的webdoclet注<br />　　 释，生成web.xml,struts-config.xml等配置信息文件--&gt;<br />　　 &lt;fileset dir="src/web"/&gt;<br />　　 &lt;fileset dir="${build.dir}/web/gen"/&gt;<br />　　 &lt;!—生成的web.xml文件放在build/appName/WEB-INF/--&gt;<br />　　 &lt;deploymentdescriptor validateXML="true"<br />　　 servletspec="2.3" sessiontimeout="10"<br />　　 destdir="${webapp.target}/WEB-INF" distributable="false"<br />　　 displayname="${ant.project.name}"&gt;<br />　　 &lt;configParam name="httpPort" value="${http.port}"/&gt;<br />　　 &lt;configParam name="httpsPort" value="${https.port}"/&gt;<br />　　 &lt;configParam name="daoType" value="${dao.type}"/&gt;<br />　　 &lt;configParam name="security" value="${security.mode}"/&gt;<br />　　 &lt;/deploymentdescriptor&gt;<br />　　 &lt;jsptaglib validateXML="true"<br />　　 description="Custom tag library for this application"<br />　　 shortName="${webapp.name}" filename="${webapp.name}.tld"/&gt;<br />　　 &lt;strutsconfigxml validateXML="true" version="1.2"/&gt;<br />　　 &lt;strutsvalidationxml/&gt;<br />　　 &lt;/webdoclet&gt;<br />　　 &lt;/target&gt;<br />　　 <br />　　图表 1引用一张网友发表的非常直观的使用说明图<br />　　Ø XDoclet 中的合并点 <br />　　在 XDoclet 的文档中，您会非常频繁地看到术语 合并点（merge point）和 合并文件（merge file）。合并文件是文本文件，您可以把它合并到 XDoclet 生成代码的指定位置——“合并点”上（由模板指定）。可以用合并文件来包含静态文本（例如代码片断和 XML 片断），这些文本可能很难或者不能用 XDoclet 的能力生成。例如，在示例代码的 metadata/web 目录下，您会找到这些文件。在代码生成期间，可以用到这些文件合并配置文件的一部分[引用]。 <br />　　 <br />　　ØXDoclet中的模板<br />　　XDoclet使用代码模板来生成代码。模板(template)是你想生成文件的原型。模板里使<br />　　用一些XML标签来指导模板引擎如何根据输入类以及它们的元数据来调整代码的生成。<br />　　模板有点像JSP文件。它们都包含文件和XML标签，生成输出文件时XML标签会被解析，<br />　　然后生成文本并显示在XML标签所处的位置上。除了以XDt为命名空间打头的XML标签<br />　　会被XDoclet引擎解析以外，其余的XML标签XDoclet会忽略不管。<br />　　Ø AppFuse中生成Action类的XDoclet模板<br />　　public final class &lt;XDtClass:className/&gt;Action extends BaseAction {<br />　　public ActionForward cancel(ActionMapping mapping, ActionForm form,HttpServletRequest request,<br />　　 HttpServletResponse response)<br />　　 throws Exception {<br />　　 return search(mapping, form, request, response);<br />　　 }<br />　　 public ActionForward delete(ActionMapping mapping, ActionForm form,<br />　　 HttpServletRequest request,<br />　　 HttpServletResponse response)<br />　　 throws Exception {<br />　　 if (log.isDebugEnabled()) {<br />　　 log.debug("Entering 'delete' method");<br />　　 }<br />　　 ActionMessages messages = new ActionMessages();<br />　　 &lt;XDtClass:className/&gt;Form &lt;XDtForm:classNameLower/&gt;Form = (&lt;XDtClass:className/&gt;Form) form;<br />　　 // Exceptions are caught by ActionExceptionHandler<br />　　 Manager mgr = (Manager) getBean("manager");<br />　　 mgr.removeObject(&lt;XDtClass:className/&gt;.class, new Long(&lt;XDtForm:classNameLower/&gt;Form.getId()));<br />　　 messages.add(ActionMessages.GLOBAL_MESSAGE,<br />　　 new ActionMessage("&lt;XDtForm:classNameLower/&gt;.deleted"));<br />　　 // save messages in session, so they'll survive the redirect<br />　　 saveMessages(request.getSession(), messages);<br />　　 return search(mapping, form, request, response);<br />　　 }<br />　　… …<br />　　}<br />　　Ø AppFuse中自动生成的对应Action类<br />　　public final class PersonAction extends BaseAction {<br />　　 public ActionForward cancel(ActionMapping mapping, ActionForm form,<br />　　 HttpServletRequest request,<br />　　 HttpServletResponse response)<br />　　 throws Exception {<br />　　 return search(mapping, form, request, response);<br />　　 }<br />　　 <br />　　 public ActionForward delete(ActionMapping mapping, ActionForm form,<br />　　 HttpServletRequest request,<br />　　 HttpServletResponse response)<br />　　 throws Exception {<br />　　 if (log.isDebugEnabled()) {<br />　　 log.debug("Entering 'delete' method");<br />　　 }<br />　　 ActionMessages messages = new ActionMessages();<br />　　 PersonForm personForm = (PersonForm) form;<br />　　 // Exceptions are caught by ActionExceptionHandler<br />　　 Manager mgr = (Manager) getBean("manager");<br />　　 mgr.removeObject(Person.class, new Long(personForm.getId()));<br />　　 messages.add(ActionMessages.GLOBAL_MESSAGE,<br />　　 new ActionMessage("person.deleted"));<br />　　 // save messages in session, so they'll survive the redirect<br />　　 saveMessages(request.getSession(), messages);<br />　　 return search(mapping, form, request, response);<br />　　 }<br />　　… …<br />　　} <img src ="http://www.blogjava.net/xzclog/aggbug/79160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 09:00 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XDoclet起步（转自cjsdn）</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79158.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:34:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79158.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79158.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79158.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79158.html</trackback:ping><description><![CDATA[
		<p>
				<span class="javascript" id="text132979">XDoclet起步<br /><br />XDoclet是一个代码生成工具，它可以把你从Java开发过程中繁重的重复劳动中解脱出来。XDoclet可以让你的应用系统开发的更加快速，而你只要付比原先更少的努力。你可以把你手头上的冗长而又必需的代码交给它帮你完成，你可以逃脱“deployment descriptor地狱”，你还可以使你的应用系统更加易于管理。而你所要做的，只不过是在你的注释里，多加一些类javadoc属性。然后，你会惊讶于XDoclet为了做到的一切。<br />讨论XDoclet，有一点比较容易产生混淆，那就是XDoclet不但是一系统的代码生成应用程序，而且它本身还是一个代码生成框架。虽然每个应用系统的细节千变万化（比如EJB代码生成和Struts代码生成是不一样的，而JMX代码生成又是另一番景象），但这些代码生成的核心概念和用法却是类似的。<br />在这一章里，我们将会看到渗透到所有XDoclet代码生成程序当中的XDoclet框架基础概念。但在之前，我们先从一个例子入手。<br /><br />2.1 XDoclet in action<br /><br />每一个程序员都会认识到，他们的程序永远也不会完成。总会有另一些的功能需要添加，另一些的BUG需要修正，或者需要不断的进行重构。所以，在代码里添加注释，提醒自己（或者其他的程序员）有哪些任务需要完成已成为一个共识。<br />如何来跟踪这些任务是否完成了呢？理想情况下，你会收集整理出来一个TODO任务列表。在这方面，XDoclet提供了一个强大的TODO生成器，来帮助你完成这个任务。这是一个把XDoclet引入项目的好机会。<br />2.1.1 一个公共的任务<br />假设你正在开发一个使用了勺子的类。<br />public class Matrix {<br />　　// TODO – 需要处理当没有勺子的情况<br />　　public void reload() {<br />　　　　// ...<br />　　　　Spoon spoon = getSpoon();<br />　　　　// ...<br />　　}<br />}<br />理想情况下，你在下一次阅读这段代码的时候，你会处理这个“空勺子”(null spoon)的问题。但如果你过了很久才回来看这段代码，你还会记得在这个类里还有一些工作要做吗？当然，你可以在你的源码里全局搜索TODO，甚至你的集成开发环境有一个内建的TODO列表支持。但如果你想把任务所在的类和方法也标注出来的话，XDoclet可以是另一种选择。XDoclet可以为你的项目生成一个TODO报表。<br /><br />2.1.2 添加XDoclet标签<br />为了把你的TODO项目转换成另一种更加正式的格式，你需要对代码进行一些细微的改动。如下所示：<br />public class Matrix {<br />　　/** @todo 需要处理当没有勺子的情况 */<br />　　public void reload() {<br />　　　　// ...<br />　　}<br />}<br />这里加入了一个XDoclet需要的类javadoc标签。XDoclet会使用这些标签标记的信息，以及在这种情况下标签所处的类和方法，来生成TODO报表。<br /><br />2.1.3 与Ant集成<br />要生成TODO报表，你需要确保在你的机器上正确安装了XDoclet。<br />在Ant任务里，最少要包含一个目标（例如init目标）定义&lt;documentdoclet&gt;任务，这是一个Ant自定义任务，例如：<br />　　&lt;taskdef name=”documentdoclet”<br />　　　　classname=”xdoclet.modules.doc.DocumentDocletTask”<br />　　　　classname=”xdoclet.lib.path” /&gt;<br />这个&lt;documentdoclet&gt;任务是XDoclet核心代码生成应用程序中的一个。<br />现在，你可以在Ant构建文件中加入一个todo目标调用这个任务来生成TODO报表，如：<br />　　&lt;target name=”todo” depends=”init”&gt;<br />　　　　&lt;documentdoclet destdir=”todo”&gt;<br />　　　　　　&lt;fileset dir=”${dir.src}”&gt;<br />　　　　　　　　&lt;include name=”**/*.java” /&gt;<br />　　　　　　&lt;/fileset&gt;<br />　　　　　　&lt;info/&gt;<br />　　　　&lt;/documentdoclet&gt;<br />　　&lt;/target&gt;<br />&lt;info&gt;子任务会遍历你的源文件，查找todo标签，并在todo子目录下生成HTML格式的TODO报表。<br /><br />2.1.4 创建一个更加职业化的TODO报表<br />XDoclet生成的TODO报表可以有一个更加职业化的外表。报表会列出一个概览，显示在哪个包哪个类里有todo项（以及todo项的个数）。Todo项可以跟在方法、类和域上，从报表上可以清楚的区别它们。类级别的todo项会标注class，方法级别的todo项会在方法签名上标注M。构造函数和域相关的todo项也会进行相似的标注。<br />这个任务看起来很简单，但考虑到你所需要做的只是在注释上添加一些格式化的@todo标签，相对于那种只有人才可以理解的无格式的松散的注释，这种标签是机器可读的，也更容易编程处理。生成的输出也更容易阅读并且更加的商业化。<br /><br />2.2 任务和子任务<br />生成todo报表，只是XDoclet可以完成的事情当中的冰山一角。当初，XDoclet因为可以自动生成EJB繁杂的接口和布署描述文件而声名鹊起。然而，现在的XDoclet已经发展成了一个全功能的、面向属性的代码生成框架。J2EE代码生成只是XDoclet的一个应用方面，它可以完成的任务已经远远超越了J2EE和项目文档的生成。<br /><br />2.2.1 XDoclet 任务<br />到现在为止，我们一直在讨论使用XDoclet生成代码，但事实上，更确切的说法应该是，我们使用XDoclet的一个特定的任务来生成代码，比如&lt;ejbdoclet&gt;。每一个XDoclet任务关注于一个特定的领域，并提供这个领域的丰富的代码生成工具。<br />[定义：任务（Tasks）是XDoclet里可用的代码生成应用程序的高层概念。]<br />在XDoclet里，目前已有如下所示的七个核心任务。<br />&lt;ejbdoclet&gt;：面向EJB领域，生成EJB、工具类和布署描述符。<br />&lt;webdoclet&gt;：面向Web开发，生成serlvet、自定义标签库和web框架文件。<br />&lt;hibernatedoclet&gt;：Hibernate持续，配置文件、Mbeans<br />&lt;jdodoclet&gt;：JDO，元数据，vender configuration<br />&lt;jmxdoclet&gt;：JMX，MBean接口，mlets，配置文件。<br />&lt;doclet&gt;：使用用户自定义模板来生成代码。<br />&lt;documentdoclet&gt;：生成项目文件（例如todo列报表）<br />这其中，&lt;ejbdoclet&gt;最常用，并且很多项目也仅仅使用XDoclet来进行EJB代码生成。&lt;webdoclet&gt;是其次一个常用的代码生成任务。当然，在一个项目中同时使用几个XDoclet任务是可能的（并且也是推荐的），但在这些任务之间是完全独立的，它们彼此之间并不能进行直接的交流。<br /><br />2.2.2 XDoclet子任务<br />XDoclet的任务是领域相关的，而在某个特定领域的XDoclet任务，又由许许多多紧密耦合在一起的子任务组成的，这些子任务每个都仅仅执行一个非常特定和简单的代码生成任务。<br />[定义：子任务（subtasks）是由任务提供的单目标的代码生成过程]<br />任务提供子任务执行时的上下文，并且把这些相关的子任务组织管理了起来。任务会依赖这些子任务来生成代码。在一个任务当中调用多个子任务来协同完成各种各样比较大型的代码生成任务是非常常见的。比如，在开发EJB时，你可能想要为每一个bean生成一个home接口，一个remote接口以及ejb-jar.xml布署描述符文件。这就是在&lt;ejbdoclet&gt;任务的上下文环境中的三个独立的代码生成子任务。<br />子任务可以随意的组合排列，以满足项目代码生成的需要。某个XDoclet任务包含的子任务经常会共享功能和在源文件中使用相同的XDoclet标签。这意味着当你开始一个任务的时候，你可以很容易的集成进一个相关的子任务，而不需要很大的改动。<br /><br />子任务交互<br />让我们以&lt;ejbdoclet&gt;任务为例，看一下相关的子任务之间是如何进行关联的。假设你正在开发一个CMP（容器管理持久化）实体Bean。你想要使用一些&lt;ejbdoclet&gt;的子任务：<br />•&lt;deploymentdescriptor&gt;：生成ejb-jar.xml布署描述符文件。<br />•&lt;localhomeinterface&gt;：生成local home接口。<br />•&lt;localinterface&gt;：生成local接口。<br />在执行如上子任务的时候，你需要标记出你的实体Bean的CMP域。当你发布你的bean的时候，你还需要在开发商相关的布署描述符中提供某个特定的关系数据库中的特定表和列与你的CMP实体Bean的映射关系。XDoclet可以让你在原先已存在的CMP XDoclet属性基础上再加上一些关系映射属性，然后，你就可以在任务中加入一个开发商相关的子任务（例如&lt;jboss&gt;或者&lt;weblogic&gt;）来生成布署描述符文件。XDoclet提供了几乎所有的应用服务器的支持，你只需要一些初始化的小改动，就可以进行这些应用服务器相关的代码生成了。<br />但那只是冰山一角。你还可以使用&lt;entitycmp&gt;子任务为为你的bean生成一个实体bean接口的实现子类。如果你使用&lt;valueobject&gt;子任务来为了你的bean生成值对象，&lt;entityemp&gt;子任务还会为你的值对象生成方法的实现代码。<br />觉得不可思议了吧。可惜XDoclet没有提供&lt;cupofcoffee&gt;子任务，要不然我们可以喝杯咖啡，休息一下啦。<br />这里不是想向你介绍&lt;ejbdoclet&gt;所有的子任务或者&lt;ejbdoclet&gt;可以完成的所有代码生成功能，而仅仅是想向你展示一下任务的子任务之间是如何工作在一起的。一旦你开始并熟悉了一个XDoclet 子任务，熟悉另一个子任务会变得非常简单- 那种每个子任务都是孤立的相比，使用这种可以相互协作的子任务，开发成本会显著的降低，效果也更加的立竿见影。 </span>
				<br />
				<br />
				<span class="javascript" id="text133004">2.3 使用Ant执行任务<br />XDoclet“嫁”给了Ant。XDoclet任务就是Ant的自定义任务，除此以外，没有其他运行XDoclet任务的方法。所幸的是，Ant已经成为了Java构建工具事实上的标准，所以这不算什么限制。事实上，反过来，XDoclet与Ant的这种“亲密”关系使得XDoclet可以参与到任何Ant构建过程当中去。<br />2.3.1 声明任务<br />XDoclet并没有和Ant一起发布，所以如果你想要使用XDoclet的话，就需要单独的下载和安装。在使用任何一个XDoclet的任务之前，你首先需要在使用Ant的&lt;taskdef&gt;任务来声明它。例如：<br />&lt;taskdef name=”ejbdoclet”<br />　　classname=”xdoclet.modules.ejb.EjbDocletTask”<br />　　classpathref=”xdoclet.lib.path”/&gt;<br />如果你熟悉Ant的话，你就会知道这段代码是告诉Ant加载&lt;ejbdoclet&gt;的任务定义。当然，你也可以以你喜欢的任何方式来命名这个自定义任务，但最好还是遵守标准的命名规律以免发生混淆。classname和classpathref属性告诉Ant到哪里去找实现这个自定义任务的XDoclet类。如果你想使用其他的XDoclet任务，就必须要类似这样首先声明这个任务。<br />一般共通的做法是，把所有需要使用的XDoclet任务都放在Ant的一个目标里声明，这样在其他的目标里如果需要使用这些任务，只要depends这个任务就可以了。你可能已经在Ant的构建文件里包含了init目标，这就是放置XDoclet任务声明的好地方（当然如果你没有，你也可以建一个）。下面的例子就是在一个init目标里加入了&lt;ejbdoclet&gt;和&lt;webdoclet&gt;的声明：<br />&lt;target name=”init”&gt;<br />　　&lt;taskdef name=”documentdoclet”<br />　　　　classname=”xdoclet.modules.doc.DocumentDocletTask”<br />　　　　classpathref=”xdoclet.lib.path” /&gt;<br />　　　　&lt;taskdef name=”ejbdoclet”<br />　　　　　　classname=”xdoclet.modules.ejb.EjbDocletTask”<br />　　　　　　classpathref=”xdoclet.lib.path” /&gt;<br />　　　　&lt;taskdef name=”webdoclet”<br />　　　　　　classname=”xdoclet.modules.web.WebDocletTask”<br />　　　　　　classpathref=”xdoclet.lib.path” /&gt;<br />&lt;/target&gt;<br />现在，任务声明好了，XDoclet“整装待发”。<br /><br />2.3.2 使用任务<br />你可以在任何目标里使用声明好的任务。在任务的上下文环境里，可以调动相关的子任务。让我们看一个例子，这个例子调用了&lt;ejbdoclet&gt;任务。不要担心看不懂语法的细节，现在你只需要关心一些基础概念就可以了。<br />&lt;target name=”generateEjb” depends=”init”&gt;<br />　　&lt;ejbdoclet destdir=”${gen.src.dir}”&gt;<br />　　　　&lt;fileset dir=”${src.dir}”&gt;<br />　　　　　　&lt;include name=”**/*Bean.java”/&gt;<br />　　　　&lt;/fileset&gt;<br />　　&lt;deploymentdescriptor destdir=”${ejb.deployment.dir}”/&gt;<br />　　&lt;homeinterface/&gt;<br />　　&lt;remoteinterface/&gt;<br />　　&lt;localinterface/&gt;<br />　　　&lt;localhomeinterface/&gt;<br />　　&lt;/ejbdoclet&gt;<br />&lt;/target&gt;<br />把任务想像成一个子程序运行时需要的一个配置环境（记住，子任务才是真正进行代码生成工作的）。当调用一个子任务时，子任务从任务继承上下文环境，当然，你也可以根据需要随意的覆盖这些值。在上面的例子里，因为&lt;deploymentdescriptor&gt;子任务生成的布署描述符文件和其他生成各种接口的子任务生成的Java源文件需要放在不同的位置，所以覆盖了destdir的属性值。布署描述符文件需要放在一个在打包EJB JAR文件的时候可以容易包含进来的地方，而生成的Java代码则需要放置在一个可以调用Java编译器进行编译的地方。需要这些子任务之间是紧密关联的，但只要你需要，你可以有足够的自主权控制任务的生成环境。<br />&lt;fileset&gt;属性同样被应用到所有的子任务。这是一个Ant的复杂类型（相对于文本和数值的简单类型），所以以子元素的方式在任务中声明。不要把它和子任务混为一谈。当然，如果你想在某个子任务中另外指定一个不同的输入文件集，你也可以在这个子任务中放置一个&lt;fileset&gt;子元素来覆盖它。<br />子任务的可配置选项远远不止这些。我们会在下一章继续介绍所有的任务和子任务，以及常用的配置选项。<br /><br />2.4 用属性标注你的代码<br />可重用的代码生成系统需要输入来生成感兴趣的输出。一个解析器生成器也需要一个语言描述来解析生成解析器。一个商务对象代码生成器需要领域模型来知道要生成哪些商务对象。XDoclet则需要Java源文件做为输出来生成相关的类或者布署/配置文件。<br />然而，源文件可能并没有提供代码生成所需要的所有信息。考虑一个基于servlet的应用，当你想生成web.xml文件的时候，servlet源文件仅可以提供类名和适当的servlet接口方法。其他的信息比如URI pattern映射、servlet需要的初始化参数等信息并没有涵盖。显而易见，如果class并没有提供这些信息给你，你就需要自己手动在web.xml文件时填写这些信息。<br />XDoclet当然也不会知道这些信息。幸运的是，解决方法很简单。如果所需信息在源文件时没有提供，那就提供它，做法就是在源文件里加入一些XDoclet属性。XDoclet解析源文件，提取这些属性，并把它们传递给模板，模板使用这些信息生成代码。<br /><br />2.4.1 剖析属性<br />XDoclet属性其实就是javadoc的扩展。它们在外表上和使用上都有javadoc属性一样，可以放置在javadoc文档注释里。文档注释以/**开始，*/结尾。下面是一个简单的例子：<br />/**<br />* 这是一段javadoc注释。<br />* 注释可以被分解成多行，每一行都以星号<img alt="Start" src="http://www.cjsdn.net/images/smiles/star_smile.gif" width="19" />开始。<br />*/<br />在注释里的所有文本都被视为javadoc注释，并且都能够被XDoclet访问到。注释块一般都与Java源文件中的某个实体有关，并紧跟在这个实体的前面。没有紧跟实体的注释块将不会被处理。类（或者接口）可以有注释块，方法和域也可以有自己的注释块，比如：<br />/**<br />* 类注释块<br />*/<br />public class SomeClass {<br />　　/** 域注释块 */<br />　　private int id;<br />　　/**<br />* 构造函数注释块<br />*/<br />　　public SomeClass() {<br />　　　　// ...<br />　　}<br />　　/**<br />　　 * 方法注释块<br />　　 */<br />　　public int getId() {<br />　　　　return id;<br />　　}<br />}<br />注释块分成两部分：描述部分和标签部分。当遇到第一个javadoc标签时，标签部分开始。Javadoc标签也分成两部分：标签名和标签描述。标签描述是可选的，并且可以多行。例如：<br />/**<br />* 这是描述部分<br />* @tag1 标签部分从这里开始<br />* @tag2<br />* @tag3 前面一个标签没有标签描述。<br />* 这个标签有多行标签描述。<br />*/<br />XDoclet使用参数化标签扩展了javadoc标签。在XDoclet里，你可以在javadoc标签的标签描述部分加入name=”value”参数。这个微小的改动大大增强了javadoc标签的表达能力，使得javadoc标签可以用来描述复杂的元数据。下面的代码显示了使用XDoclet属性描述实体Bean方法：<br />/**<br />* @ejb.interface-method<br />* @ejb.relation<br />* name=”blog-entries”<br />* role-name=”blog-has-entries”<br />* @ejb.value-object<br />* compose=”com.xdocletbook.blog.value.EntryValue”<br />* compose-name=”Entry”<br />* members=”com.xdocletbook.blog.interfaces.EntryLocal”<br />* members-name=”Entries”<br />* relation=”external”<br />* type=”java.util.Set”<br />*/<br />public abstract Set getEntries();<br />参数化标签允许组合逻辑上相关联的属性。你可以加入描述这个类的元信息，使得这个类的信息足够生成代码。另外，程序员借由阅读这样的元信息，可以很快的理解这个类是如何使用的。（如果这个例子上的元信息你看不懂，不要担心，在第4章里，我们会学到EJB相关的标签以及它们的涵意。）<br />另外，请注意上面的例子中，所有的标签名都以ejb开头。XDoclet使用namespace.tagname的方式给标签提供了一个命名空间。这样做除了可以跟javadoc区别开来以外，还可以把任务相关的标签组织起来，以免任务之间的标签产生混淆。 </span>
				<br />
		</p>
		<p>
				<span class="javascript" id="text133086">2.5 代码生成模式<br />XDoclet是一种基于模板的代码生成引擎。从高层视图上来看，输出文件其实就是由解析执行各式各样的模板生成出来的。如果你理解了模板以及它所执行的上下文环境，就可以确切的认识到，XDoclet可以生成什么，不可以生成什么。如果你正在评估XDoclet平台，理解这些概念是非常重要的。要不然，你可能会错过XDoclet的许多强大的功能，也可能会被XDoclet的一些限制感到迷惑。<br />XDoclet运行在在Ant构建文件环境中，它提供了Ant自定义任务和子任务来与XDoclet引擎交互。任务是子任务的容器，子任务负责执行代码生成。子任务调用模板。模板提供了你将生成代码的饼干模子。XDoclet解析输入的源文件，提取出源文件中的XDoclet属性元数据，再把这些数据提供给模板，驱动模板执行。除此之外，模板还可以提供合并点(merge points)，允许用户插入一些模板片断(合并文件merge files)来根据需要定制代码生成。<br />2.5.1 模板基础<br />XDoclet使用代码模板来生成代码。模板(template)是你想生成文件的原型。模板里使用一些XML标签来指导模板引擎如何根据输入类以及它们的元数据来调整代码的生成。<br />[定义：模板(template)是生成代码或描述文件的抽象模视图。当模板被解析的时候，指定的细节信息会被填入。]<br />模板一般情况下会有一个执行环境。模板可能应用在一个类环境(转换生成transform generation)，也有可能应用在一个全局环境(聚集生成aggregate generation)。转换生成和聚集生成是XDoclet的两种类型的任务模式，理解它们之间的区别对于理解XDoclet是非常重要的。<br />当你使用XDoclet生成布置描述符文件时，你使用的是聚集生成。布置描述符文件并不仅仅只与一个类相关，相反，它需要从多个类里聚集信息到一个输入文件。在这种生成模式里，解析一次模板只会生成一个输出文件，不管有多少个输入文件。<br />在转换生成模式里，模板遇到每一个源文件就会解析一次，根据该文件类的上下文环境生成输出。这种生成模式会为每一个输入文件生成一个输出文件。<br />转换生成模式的一个很好的例子是生成EJB的local和remote接口。显然，接口是和Bean类一一相关的。从每一个类里提取信息(类以及它的方法、域、接口以及XDoclet属性等信息)转换出接口。除此以外，不需要其他的信息。<br />从实现里提取出接口似乎有点反向。如果你手写程序的话，一般来说会先定义一个接口，然后再写一个类来关现它。但XDoclet做不到，XDoclet不可能帮你实现一个已有接口，因为它不可能帮你生成你的业务逻辑。当然，如果业务逻辑可以从接口本身得到(比如JavaBean的get/set访问器)或者使用XDoclet属性声明好，那么生成业务逻辑代码来实现一个接口也不是不可能。但一般情况下，这样做不太现实。相比而言，提供一个实现，并描述接口与这个实现之间的关联就容易多了。<br />聚集生成和转换生成主要区别在它们的环境信息上。即使一个代码生成任务中生成一个Java文件，一般也不常用聚集生成，因为生成一个Java类还需要一些重要信息如类所处的包以及你想生成的类名，在这种环境下是无法提供的。如果一定要使用聚集生成的话，那就需要在另一个单独的地方提供好配置信息了。<br />2.5.2 模板标签<br />在还没见到模板长啥样子之前，我们已经比较深入的认识它了。那模板文件究竟长啥样子呢？它有点像JSP文件。它们都包含文件和XML标签，生成输出文件时XML标签会被解析，然后生成文本并显示在XML标签所处的位置上。除了以XDt为命名空间打头的XML标签会被XDoclet引擎解析以外，其余的XML标签XDoclet会忽略不管。下面的代码片断显示了XDoclet模板的“经典造型”：<br />　　public class<br />　　　　&lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　Extends Observabe {<br />　　　　static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　　　_instance = null;<br />　　　　public static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClassOf&gt;<br />　　　　　　getInstance() {<br />　　　　　　if (_instance == null) {<br />　　　　　　　　_instance =<br />new &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;<br />　　　　　　　　　　&lt;/XDtClass:classOf&gt;();<br />　　　　　　｝<br />　　　　　　return _instance;<br />}<br />}<br />研究一下这个模板，你会发现，它生成的是一个类定义。这个类里定义了一个静态变量instance，并且使用一个静态方法来控制这个静态文件的访问。借助Java语法，你可以很容易的推断出那些XDoclet模板标签的目录是生成类名，虽然对于这个标签如何工作你还并不是很了解。<br />即使你从没打算过要自己写模板，但理解模板是如何被解析运行的还是很有必要的。迟早你会调用到一个运行失败的XDoclet任务，没有产生你所期望的输出，那么最快捷的找出原因的方法就是直接检查模板文件，看看是哪里出了问题。<br />让我们看一下生成静态域定义的片断：<br />static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　_instance = null;<br />在XDoclet的眼里，这段模板代码很简单，那就是：<br />　　static &lt;tag/&gt; _instance = null;<br />XDoclet解析执行标签，如果有输出的话，把输入置回到文本里去。有些标签会执行一些运算，把输出放回到一个流里。这样的标签称之为内容标签(content tags)，因为它们产生内容。<br />另一种类型的标签称之为BODY标签。BODY标签在开始和结束标签之间存在文本。而BODY标签强大就强大在这些文本自己也可以是一断可以由外围标签解析的模板片断。比如在上面的例子里，XDtClass:classOf标签，它们的内容就是模板片断：<br />　　&lt;XDtEjbFacade:remoteFacadeClass/&gt;<br />classOf标签解析这段模板，提取出全限制的内容，然后剃除前面的包面，只输出类名。BODY标签并不总是会解析它的内容，在做这件事之前，它们会事先检查一些外部判断条件(比如检查检查你正在生成的是一个接口还是一个类)。这里标标签称之为条件标签(conditional tags)。还有一些BODY标签提供类似迭代的功能，它的内容会被解析多次。比如一个标签针对类里的每一个方法解析一次内容。<br />XDoclet标签提供了许多高层次的代码生成功能，但是有时候，它们可能显得不够灵活，或者表达能力满足不了你的需要。这时候，相对于另外开发一套通用功能的模板引擎相比，你可以选择扩展XDoclet模板引擎。你可以使用更具表述能力、功能更加强大的Java平台开发你自己的一套标签。 </span>
				<br />
				<br />
				<span class="javascript" id="text133090">2.6 使用合并定制<br />代码生成系统之所以使用的不多，主要原因就在于它们往往只能生成一些死板的、不够灵活的代码。大多数代码生成系统不允许你改动它们生成的代码；如果，如果这个系统不够灵活，你所能做到的最好的扩展就是应用继承扩展生成的代码，或者使用一些共通的设计模式(比如Proxy和Adaptor)来满足你的需要。无论如此，这都不是产生你想生成的代码的好办法。代码生成器最好能做到所生成即所得WYGIWYG(what you generate is what you get)，来取代你需要花费大量的时间来粉饰生成出来的并不满足要求的代码。所以，对于代码生成器来说，支持灵活的定制，是生成能够完全满足要求的代码的前提条件。<br />XDoclet通过合并点(merge points)支持定制——合并点是在模板文件定义里允许运行时插入定制代码的地方。有时候，合并点甚至可以影响到全局代码的生成，不但允许你添加一些定制内容，还可以从根本上改变将要生成出来的东西。<br />[定义：合并点(Merge points)是模板预先定义的允许你在代码生成的运行时加入定制内容的扩展点]<br />让我们研究一段从XDoclet源代码里摘取出来的模板代码。在为实体Bean生成主键的模板末尾，定义了这样一个合并点：<br />　　&lt;XDtMerge:merge file=”entitypk-custom.xdt”&gt;&lt;/XDtMerge:merge&gt;<br />如果你在你的merge目录下创建了一个名为entitypk-custom.xdt文件，那么这个模板文件的内容将会在这个合并点被包含进来。你的定制可以执行高层模板可以执行的所有强大功能，可以进行所有模板可以进行的运算(包括定义自定义标签，定义它们自己的合并点)。<br />上面的这种合并点，为所有的类环境使用了同一个文件。当然，也可以为每一个类环境使用不同的合并文件。如果你不想定制全部的类文件，或者你不想为了某些改动而重写模板的时候，这会很有用。不管动机是什么，逐类的合并点很容易识别出来：他们会在名字里包含一个XDoclet的逐类标记{0}。这里有一个生成ejb-jar.xml文件里的安全角色引用的例子：<br />　　&lt;XDtMerge:merge file=”ejb-sec-rolerefs-{0}.xml”&gt;<br />　　　　&lt;XDtClass:forAllClassTags tagName=”ejb:security-role-ref”&gt;<br />　　　　　　&lt;security-role-ref&gt;<br />　　　　　　　　&lt;role-name&gt;<br />&lt;XDtClass:classTagValue<br />tagName=”ejb:security-roleref”<br />paramName=”role-name”/&gt;<br />　　　　　　　　&lt;/role-name&gt;<br />　　　　　　　　&lt;role-link&gt;<br />　　　　　　　　　　&lt;XDtClass:classTagValue<br />　　　　　　　　　　　　tagName=”ejb:security-roleref”<br />　　　　　　　　　　　　paramName=”role-link”/&gt;<br />　　　　　　　　&lt;/role-link&gt;<br />　　　　　　&lt;/security-role-ref&gt;<br />　　　　&lt;/XDtClass:forAllClassTags&gt;<br />　　&lt;/XDtMerge:merge&gt;<br />这段模板会遍历工程里的所有Bean。对于每一个Bean，XDoclet先从Bean的文件名里提取出Bean名，然后替换{0}，再根据替换后的文件名去寻找合并文件。例如，如果你有一个名为BlogFacadeBean的Bean，XDoclet会尝试寻找一个名为ejb-src-rolerefs-BlogFacade.xml的合并文件。<br />如果找不到这个合并文件，则这个&lt;merge&gt;标签的内容模板会被解析。这意味着合并点不仅可以提供定制内容，还可以在一个模板文件里定义一个替换点，当定制内容不存在的时候使用替换点里的内容。不是所有的XDoclet任务都提供了有替换内容的合并点，一般来说，它们更倾向于只提供一个简单的合并点，仅仅当合并文件存在的时候解析并导入合并文件的内容。这取决于任务的开发者觉得哪种合并点更符合他的要求。<br />还有一点没有介绍到的是XDoclet如何定位合并文件，每一个XDoclet任务或者子任务都会提供一个mergeDir属性，这个属性用于设置你存放合并文件的目录。 </span>
		</p>
<img src ="http://www.blogjava.net/xzclog/aggbug/79158.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:34 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>定制自己的xDoclet标签</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79156.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:33:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79156.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79156.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79156.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79156.html</trackback:ping><description><![CDATA[
		<div style="CLEAR: right">
				<span class="myp111">
						<font id="zoom">xDoclet是一种通过读取JAVA源文件中的特定标签，然后生成指定文件的工具。xDoclet标签本身已经提供了一些常用的标签，例如@ejb，@hibernate，@web等等，但是仍然不能满足我们的需求。 <br /><br /><br />例如我们最新的项目中引用了一个javascript验证框架，通过配置特定的xml配置文件，即可完成客户端表单验证，但是不想开发人员再去学习一套框架，于是想让开发人员在源代码中写@javascript这样的标签，然后生成其配置文件。 <br /><br /><br />javascript客户端验证一直是web开发中一个比较头疼的问题，经常是每一个页面中充斥着许多类似甚至相同的验证代码，如何统一有效的管理这些代码，以及如何做到代码页面的分离一直没有太好的解决方法。 <br /><br /><br />运用这个验证框架那么客户端开发就变成了配置validation-config.xml这个文件如此轻松了，本文并不打算详细讲述如何使用JSValidation框架，有兴趣的朋友可以去http://www.cosoft.org.cn/projects/jsvalidation JSValidation的官方网站自己去学习。 <br /><br /><br />虽然运用这框架已经可以很好的完成客户端验证代码的编写，并且提供了dtd文件进行xml文件的，但是手动编写xml文件还是很容易出错，效率比较低，而且新的开发人员还要掌握一个全新的框架，不宜于开发人员入门。 <br /><br /><br />像Struts或JSF这样的框架大都需要为表单写一个类似FormBean的东西，以JSF为例，假如表单内有一文本框<input type="”text”" name="”txtUsername”" />，那么对应的Page类或叫FormBean类就应有如下代码： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;private HtmlInputText txtUsername = new HtmlInputText();
<br />/**
<br />* @return 用户名
<br />*/
<br />public HtmlInputText getTxtUsername ()
<br />{
<br />    return txtUsername;
<br />}
<br />/**
<br /> * @param text
<br /> */
<br />public void setTxtTeaName(HtmlInputText text)
<br />{
<br />    txtTeaName = text;
<br />}&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />如果可以利用xDoclet，那么，就可以自动生成JSValidation的配置文件了，而且还利于培训新的开发人员，再加入ant task还可以形成每日构建。想象的代码应该是下面这个样子： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;/**
<br /> * @javascript.field
<br /> * name="frmZBAddGlobalPage:txtTeaName"
<br /> * display-name="用户名"
<br /> * 
<br /> * @javascript.depend
<br /> * name="required"
<br /> *
<br /> * @return用户名
<br /> */
<br /> public HtmlInputText getTxtUsername()
<br /> {
<br />     return txtUsername;
<br /> }&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />通过分析xDoclet自带的一些标签包，发现只需要提供三个文件即可实现自定义xDoclet标签：一个继承于XmlSubTask的类，一个继承于DocletTask的类（用于ant），一个xdt的模板语言文件即可。 <br /><br /><br />在XmlSubTask类中，首先，定义模板文件名：<br />private static String DEFAULT_TEMPLATE_FILE ="resources/validation-config.xdt"; <br /><br /><br />定义dtd文件名：<br />private final static String DTD_FILE_NAME_20 ="resources/validation-config.dtd"; <br /><br /><br />定义要生成的配置文件名：<br />private static String GENERATED_FILE_NAME = "validation-config.xml"; <br /><br /><br />然后只需将三个文件组合起来既可，详细代码如下： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;public javascriptSubTask()
<br />    {
<br />        setTemplateURL(getClass().getResource(DEFAULT_TEMPLATE_FILE));
<br />        setDestinationFile(GENERATED_FILE_NAME);
<br />    }
<br /><br />    public void execute() throws XDocletException
<br />    {
<br />        setDtdURL(getClass().getResource(DTD_FILE_NAME_20));
<br />        startProcess();
<br />    }
<br /><br />    protected void engineStarted() throws XDocletException
<br />    {
<br />        System.out.println(
<br />            Translator.getString(
<br />                XDocletMessages.class,
<br />                XDocletMessages.GENERATING_SOMETHING,
<br />                new String[] { getDestinationFile()}));
<br />    }&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />要想ant可以使用，只需要以下简单的代码： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;/*
<br /> * 创建日期 2004-4-26
<br /> */
<br />package paradise.xdoclet.modules.javascript;
<br /><br />import xdoclet.DocletTask;
<br /><br />/**
<br /> * @author 清风
<br /> */
<br />public class javascriptDocletTask extends DocletTask
<br />{
<br />    public javascriptDocletTask()
<br />    {
<br />        addSubTask(new javascriptSubTask());
<br />    }
<br />}&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />在ant中按如下方式定义： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;&lt;target name="javascript" depends="jxdoc_init" 
<br />description="Generate javascript validation-config"&gt;
<br />        &lt;javascriptdoclet destdir="${jsp}/javascript"&gt;
<br />            &lt;fileset dir="${src}"&gt;
<br />                &lt;include name="**/zaibian/*.java"/&gt;
<br />            &lt;/fileset&gt;
<br />        &lt;/javascriptdoclet&gt;
<br />&lt;/target&gt;&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />接下来，也是最核心的部分，就是有关xdt模板语言，xdt文件可以说是自定义xDoclet标签的最重要的文件之一，以javascriptxDoclet为例，简单介绍一下xdt模板语言： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;&lt;XDtClass:forAllClasses&gt;    遍历所有含有标签的类（在ant中指定）
<br />&lt;XDtMethod:forAllMethods&gt;    遍历当前类的所有方法
<br />&lt;XDtMethod:ifHasMethodTag tagName="javascript.form"&gt;    如果遍历到的方法中含有指定的标签
<br />&lt;XDtMethod:forAllMethodTags tagName="javascript.depend"&gt;    遍历当前方法的所有标签&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />更多的模板语言，参考xDoclet的.XDT文档，都是很好理解的模板语言。 <br /><br /><br />接下来，开始自定义自己的标签，新建一个xtags.xml文件，加上开头 <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;
<br /><br />&lt;!DOCTYPE xdoclet PUBLIC "-//XDoclet Team//DTD XDoclet Tags 1.1//EN" 
<br />"http://xdoclet.sourceforge.net/dtds/xtags_1_1.dtd"&gt;&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />然后写下所有自定义的标签，例如： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;&lt;xdoclet&gt;
<br />    &lt;namespace&gt;
<br />        &lt;name&gt;javascript&lt;/name&gt;
<br />        &lt;tags&gt;
<br />            &lt;tag&gt;
<br />                &lt;level&gt;method&lt;/level&gt;
<br />                &lt;name&gt;javascript.form&lt;/name&gt;
<br />                &lt;usage-description&gt;Form&lt;/usage-description&gt;
<br />                &lt;condition type="method"/&gt;
<br />                &lt;parameter type="text"&gt;
<br />                    &lt;name&gt;id&lt;/name&gt;
<br />                    &lt;usage-description&gt;Form id&lt;/usage-description&gt;
<br />                    &lt;mandatory&gt;true&lt;/mandatory&gt;
<br />                &lt;/parameter&gt;
<br />                &lt;parameter type="text"&gt;
<br />                    &lt;name&gt;show-error&lt;/name&gt;
<br />                    &lt;usage-description&gt;Form Error Display&lt;/usage-description&gt;
<br />                    &lt;mandatory&gt;true&lt;/mandatory&gt;
<br />                &lt;/parameter&gt;
<br />                &lt;parameter type="text"&gt;
<br />                    &lt;name&gt;onfail&lt;/name&gt;
<br />                    &lt;usage-description&gt;Form Error Run Custom javascript Function&lt;/usage-description&gt;
<br />                    &lt;mandatory&gt;false&lt;/mandatory&gt;
<br />                &lt;/parameter&gt;
<br />            &lt;/tag&gt;
<br />        &lt;/tags&gt;
<br />    &lt;/namespace&gt;
<br />&lt;/xdoclet&gt;&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />注意几个地方： <br /><br /><br />&lt;ccid_nobr&gt; <br /><table cellspacing="0" cellpadding="2" width="400" border="1"><br />bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt; <br /><tbody><tr><br /><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><br /><pre>&lt;ccid_code&gt;“&lt;level&gt; method &lt;/level&gt;”代表该标签出现在方法上而不是类之上。例如
<br />/**
<br />*@javascript.form
<br />*name=”test”
<br />*/
<br />public String getXXX()
<br />{
<br />}&lt;/ccid_code&gt;</pre><br /></td><br /></tr><br /></tbody></table><br />&lt;/ccid_nobr&gt; <br /><br /><br />最后就是将这些文件打成jar，其放置目录分别是： <br /><br /><br />根目录<br />|<br />|--META-INF/xtags.xml<br />|<br />|--源代码<br />|----|<br />|----|--resources/*.xdt,*.dtd <br /></font>
				</span>
				<center>
				</center>
		</div>
<img src ="http://www.blogjava.net/xzclog/aggbug/79156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:33 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>扩展XDoclet对Spring List引用注入的支持</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79155.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:32:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79155.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79155.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79155.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79155.html</trackback:ping><description><![CDATA[
		<p>XDoclet是生成配置文件的强有力的工具，在使用Spring框架时，手动编写Spring配置文件极其繁琐，而且容易遗漏，利用XDoclet即可轻松生成配置文件。</p>
		<p>XDoclet支持的Spring方法注入包括：ref，list，name和value。遗憾的是，在某个项目中，我需要注入一个包含Bean引用的List：</p>
		<pre>
				<strong>
						<font color="#339966">public void setHandlers(List handlers) {<br />  ...<br />}</font>
				</strong>
		</pre>
		<p>然后，XDoclet并不支持元素为引用类型的List，倘若使用下列注释：</p>
		<pre>
				<font color="#339966">
						<strong>/**<br /> * @spring.property list="articleHandler,imageHandler"<br /> */<br />public void setHandlers(List handlers) {<br />  ...<br />}</strong>
				</font>
		</pre>
		<p>生成的配置文件如下：</p>
		<pre>
				<strong>
						<font color="#339966">&lt;property name="handlers"&gt;<br />  &lt;list&gt;<br />    &lt;value&gt;articleHandler&lt;/value&gt;<br />    &lt;value&gt;imageHandler&lt;/value&gt;<br />  &lt;/list&gt;<br />&lt;/property&gt;</font>
				</strong>
		</pre>
		<p>毫无疑问，在Spring启动时，一个ClassCastException将被抛出，因为无法将String类型转化为我们自定义的Handler引用类型。</p>
		<p>幸运的是，XDoclet良好的可扩展性使我们能够轻松扩展需要的配置，甚至不需要我们利用XDoclet提供的API编写代码。XDoclet提供一种XML结构的模版语言来生成配置文件，对于Spring配置文件，对应的XML配置文件在<font color="#339966"><strong>xdoclet-spring-module-1.2.3.jar/xdoclet/modules/spring/resources/spring_xml.xdt</strong></font>中。</p>
		<p>解开jar包，修改spring_xml.xdt，增加如下XML片断（红色部分）：</p>
		<pre>
				<strong>
						<font color="#339966">  &lt;XDtMethod:forAllMethods superclasses="true"&gt;<br />   &lt;XDtMethod:ifHasMethodTag tagName="spring.property"&gt;<br />    &lt;property name="&lt;XDtMethod:propertyName/&gt;"&gt;<br />    &lt;XDtMethod:ifHasMethodTag tagName="spring.property" paramName="value"&gt;<br />      &lt;value&gt;&lt;XDtMethod:methodTagValue tagName="spring.property" paramName="value"/&gt;&lt;/value&gt;<br />    &lt;/XDtMethod:ifHasMethodTag&gt;<br />    &lt;XDtMethod:ifHasMethodTag tagName="spring.property" paramName="ref"&gt;<br />      &lt;ref bean="&lt;XDtMethod:methodTagValue tagName="spring.property" paramName="ref"/&gt;"/&gt;<br />    &lt;/XDtMethod:ifHasMethodTag&gt;<br />    &lt;XDtMethod:ifHasMethodTag tagName="spring.property" paramName="list"&gt;<br />      &lt;list&gt;<br />      &lt;XDtMethod:forAllMethodTagTokens tagName="spring.property" paramName="list"&gt;<br />        &lt;value&gt;&lt;XDtMethod:currentToken/&gt;&lt;/value&gt;<br />      &lt;/XDtMethod:forAllMethodTagTokens&gt;<br />      &lt;/list&gt;<br />    &lt;/XDtMethod:ifHasMethodTag&gt;</font>
				</strong>
		</pre>
		<pre>
				<strong>
						<font color="#ff0000">    &lt;XDtMethod:ifHasMethodTag tagName="spring.property" paramName="<u>list.ref</u>"&gt;<br />      &lt;list&gt;<br />        &lt;XDtMethod:forAllMethodTagTokens tagName="spring.property" paramName="list.ref"&gt;<br />          &lt;ref bean="&lt;XDtMethod:currentToken/&gt;"/&gt;<br />        &lt;/XDtMethod:forAllMethodTagTokens&gt;<br />      &lt;/list&gt;<br />    &lt;/XDtMethod:ifHasMethodTag&gt;</font>
				</strong>
		</pre>
		<pre>
				<strong>
						<font color="#339966">    &lt;/property&gt;<br />   &lt;/XDtMethod:ifHasMethodTag&gt;<br />  &lt;/XDtMethod:forAllMethods&gt;</font>
				</strong>
		</pre>
		<p>注意红色部分的代码，我们仿照list，增加一个list.ref来实现引用类型的List。<br />现在，修改注释如下：</p>
		<pre>
				<strong>
						<font color="#339966">/**<br /> * @spring.property list.ref="articleHandler,imageHandler"<br /> */<br />public void setHandlers(List handlers) {<br />  ...<br />}</font>
				</strong>
		</pre>
		<p>备份好原有的xdoclet-spring-module-1.2.3.jar，然后将修改后的目录打包：</p>
		<span style="FONT-WEIGHT: bold">
				<pre>
						<font color="#339966">jar cvf xdoclet-spring-module-1.2.3.jar .</font>
				</pre>
				<p>
				</p>
		</span>替换原来的xdoclet-spring-module-1.2.3.jar，运行XDoclet，顺利生成预期配置：<pre><strong><font color="#339966">&lt;property name="handlers"&gt;<br />  &lt;list&gt;<br />    &lt;ref bean="articleHandler"/&gt;<br />    &lt;ref bean="imageHandler"/&gt;<br />  &lt;/list&gt;<br />&lt;/property&gt;</font></strong></pre><p>类似的，我们还可以增加XDoclet对Map注入的支持。</p><img src ="http://www.blogjava.net/xzclog/aggbug/79155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:32 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Xdoclet是什么?</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79154.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:31:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79154.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79154.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79154.html</trackback:ping><description><![CDATA[
		<div style="CLEAR: right">本文的目的是让你用最短的时间了解xdoclet技术,本人并未对其作深入的研究，若理解有误请指正。<br /><br /><br /><br />XDoclet是一个开源项目，可以从这里得到他：http://xdoclet.sourceforge.net/xdoclet/ 。 <br /><br />XDoclet可以通过你在java源代码中的一些特殊的注释信息，自动为你生成配置文件、源代码等等，例如web、ejb的部署描述文件、为你生成struts的struts-config.xml配置文件、javascript校验等。<br /><br />正如《XDoclet in Action》部分章节中文版 一文中所说的“当初，XDoclet因为可以自动生成EJB繁杂的接口和布署描述文件而声名鹊起。然而，现在的XDoclet已经发展成了一个全功能的、面向属性的代码生成框架。J2EE代码生成只是XDoclet的一个应用方面，它可以完成的任务已经远远超越了J2EE和项目文档的生成。”<br /><br />目前的版本可以为web、ejb、struts、webwork、hibnaate、jdo、jmx等等生成描述文件、源码等，XDoclet提供了ant的任务target支持，完全通过ant来完成任务。<br /><br /><br /><br />展开XDoclet的发布包，samples目录下有直接可以运行的ant脚本文件。这里以web应用target为例，说明XDoclet能为我们作些什么。<br /><br />下面是samples中一个struts的action代码：<br /><br />import javax.servlet.http.HttpServletResponse;<br /><br /><br /><br />import org.apache.struts.action.Action;<br /><br />import org.apache.struts.action.ActionForm;<br /><br />import org.apache.struts.action.ActionForward;<br /><br />import org.apache.struts.action.ActionMapping;<br /><br /><br /><br />/**<br /><br />* Simple class to test Jakarta Struts generation (Jakarta Struts 1.2 beta 2 only).<br /><br />*<br /><br />* @struts.action<br /><br />* path="/struts/foo"<br /><br />*<br /><br />* @struts.action-forward<br /><br />* name="success"<br /><br />* path="/struts/getAll.do"<br /><br />* redirect="false"<br /><br />*/<br /><br />public final class StrutsAction extends Action<br /><br />{<br /><br />public ActionForward execute(ActionMapping mapping, ActionForm form,<br /><br />HttpServletRequest request, HttpServletResponse response)<br /><br />{<br /><br />return mapping.findForward("success");<br /><br />}<br /><br />}<br /><br /><br /><br />注意红色的注释部分，注意执行完ant脚本后，将为你生成struts-config.xml中相关的配置项，以下是脚本执行后生成的struts-config.xml文件中的配置：<br /><br /><br /><br /><!-- ========== Action Mapping Definitions =================================== --><br /><br />&lt;action-mappings&gt;<br /><br />&lt;action<br /><br />path="/struts/foo"<br /><br />type="test.web.StrutsAction"<br /><br />unknown="false"<br /><br />validate="true"<br /><br />&gt;<br /><br />&lt;forward<br /><br />name="success"<br /><br />path="/struts/getAll.do"<br /><br />redirect="false"<br /><br />/&gt;<br /><br />&lt;/action&gt;<br /><br /><br /><br />至此一点我们便可以了解XDoclet是如何工作的了，想想struts中的vaild配置文件、struts-config配置文件等需要我们大量的手工工作，如果再写代码的时候把相关的元数据信息写在注释里，XDoclet将为我们自动完成这些工作，当然像 @struts.action ?#162;@struts.action-forward 等这些特定的注释标签需要去查XDoclet的相关文档了，像前面说的一样，Xdoclet对目前流行的多种框架、技术都提供了相关的支持。相信在一些情况下，Xdoclet会大大提高我们的工作效率的，了解更多信息请参考Xdoclet网站http://xdoclet.sourceforge.net/xdoclet/ 。 
<center></center></div>
<img src ="http://www.blogjava.net/xzclog/aggbug/79154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:31 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用XDoclet 减少代码膨胀 </title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79153.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:30:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79153.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79153.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79153.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79153.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79153.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<p id="subtitle">发现多功能的模板驱动的代码生成器</p>
										<img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" />
								</td>
								<td class="no-print" width="192">
										<img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" />
								</td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td width="100%">
										<table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0">
												<tbody>
														<tr>
																<td width="10">
																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
																</td>
																<td>
																		<table cellspacing="0" cellpadding="0" width="150" border="0">
																				<tbody>
																						<tr>
																								<td class="v14-header-1-small">文档选项</td>
																						</tr>
																				</tbody>
																		</table>
																		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td class="no-padding" width="150">
																										<table cellspacing="0" cellpadding="0" width="143" border="0">
																												<tbody>
																														<tr valign="top">
																																<td width="8">
																																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																</td>
																																<td width="16">
																																		<img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" />
																																</td>
																																<td width="122">
																																		<p>
																																				<a class="smallplainlink" href="javascript:document.email.submit();">
																																						<strong>
																																								<font color="#5c81a7" size="2">将此页作为电子邮件发送</font>
																																						</strong>
																																				</a>
																																		</p>
																																</td>
																														</tr>
																														<noscript>
																														</noscript>
																												</tbody>
																										</table>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
																		<!-- 03/20/06 updated by gretchen -->
																		<br />
																		<table cellspacing="0" cellpadding="0" width="150" border="0">
																				<tbody>
																						<tr>
																								<td class="v14-header-2-small">最新推荐</td>
																						</tr>
																				</tbody>
																		</table>
																		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td class="no-padding" width="150">
																										<table cellspacing="0" cellpadding="0" width="143" border="0">
																												<tbody>
																														<tr valign="top">
																																<td width="8">
																																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																																</td>
																																<td>
																																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" />
																																</td>
																																<td width="125">
																																		<p>
																																				<a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/kickstart/">
																																						<font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font>
																																				</a>
																																		</p>
																																</td>
																														</tr>
																												</tbody>
																										</table>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<p>级别: 初级</p>
										<p>
												<a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#author">
														<font color="#996699">Sing Li </font>
												</a>, 作者, Wrox Press<br /></p>
										<p>2004 年 11 月 05 日</p>
										<blockquote>开放源代码的 XDoclet 代码生成引擎，是许多领先的 Java 框架不可缺少的组成部分，常常被用作面向属性的编程和持续集成的引擎。但是 XDoclet 还有一些不太惹人注目的地方：对初级开发人员来说，它太难掌握、太难精通。在这篇文章中，流行作者 Sing Li 以 XDoclet 为对象，揭示了其内部简单却优雅的设计，使您能够理解这项技术，并将它应用在实践当中。</blockquote>
										<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
										<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<p>XDoclet 能够很容易成为您的 Java 编程工具箱中的一个更加通用的跨技术代码生成工具。不幸的是，开发人员经常忽视 XDoclet 的一般用途，只有将它捆绑在大型开发框架或者 IDE 中，作为其中的一个隐藏元素时，才会用到它。人们常常认为很难将 XDoclet 应用在定制解决方案上。这篇文章的目的就是要消除这个迷惑，把 XDoclet 从常见的复杂陷阱中解脱出来，并向您展示了如何能够利用这个代码生成引擎。 </p>
										<p>我会用一个实际的例子演示 XDoclet 的用途，该例子将接收一个 POJO（plain old Java object），并用 XDoclet 生成完整 Web 应用程序的全部文件，这些文件是把数据输入关系数据库所必需的。该示例使用了 XDoclet 的 自定义模板代码生成功能，以及它对 Hibernate 对象关系映射工具、Struct Web 应用程序框架和应用程序服务器的内部支持。（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a>）。 </p>
										<p>
												<a name="simulation">
														<span class="atitle">
																<font size="4">智能代码生成器</font>
														</span>
												</a>
										</p>
										<p>XDoclet 的核心功能是根据以下组合来生成代码的（或者生成其他配置/数据文件）：</p>
										<ul>
												<li>进行特殊标记的 Java 源文件。 
</li>
												<li>预先定义的模板。 </li>
										</ul>
										<p>与其他基于模板的代码生成技术（例如 Velocity；请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a>）相比，XDoclet 具有以下独特优势： </p>
										<ul>
												<li>XDoclet 与 Apache Ant（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a>）紧密集成，从而提供了高度自动化的操作。 <br /><br /></li>
												<li>把控制代码生成和模板处理的 XDoclet 标签作为内联注释嵌入到 Java 源代码文件中。这消除了同步多个相关文件和控制文件的需要。 <br /><br /></li>
												<li>XDoclet 的内置 Java 解析器使用它对 Java 代码结构的深入理解，为输入的 Java 代码建立内部 <em>结构模型</em>。该结构模型又经常被叫作 <em>元数据（metadata）</em>，因为它包含与关联代码有关的数据。 <br /><br /></li>
												<li>XDoclet 的模板生成逻辑拥有对输入 Java 代码的内部结构模型的完全访问权。 </li>
										</ul>
										<p>接下来，我将进一步研究 XDoclet 是如何工作的，以帮助您理解这些特性。 </p>
										<p>
												<a name="inside">
														<span class="smalltitle">
																<strong>
																		<font size="3">XDoclet 操作</font>
																</strong>
														</span>
												</a>
										</p>
										<p>图 1 显示了 XDoclet 要求的输入和生成的输出。</p>
										<br />
										<a name="fig1">
												<strong>图 1. XDoclet 黑盒子</strong>
										</a>
										<br />
										<img height="549" alt="图 1" src="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/fig1.gif" width="429" />
										<br />
										<p>您可以看到，包含嵌入式 XDoclet 标签的 Java 源代码是系统的输入。在 Apache Ant 的驱动下，XDoclet 处理输入的代码，生成的输出文本文件可以是 Java 源代码、HTML 页面、XML 文件等。为了处理输入，XDoclet 需要使用模板（保存在 .xdt 文件中）和标签处理器（用 Java 编码）。XDoclet 把模板和标签处理器打包成“模块”，不同的“模块”处理不同的问题域。</p>
										<p>
												<a name="1.0">
														<span class="smalltitle">
																<strong>
																		<font size="3">XDoclet 生成的结构模型 </font>
																</strong>
														</span>
												</a>
										</p>
										<p>XDoclet 对包含嵌入式 XDoclet 标签的输入 Java 源代码进行解析，并为代码建立非常详细的结构模型。结构模型中的每个元素都代表源代码中的一个 Java 结构。图 2 显示的结构模型，揭示了 XDoclet 跟踪的代码构造和关系。 </p>
										<br />
										<a name="fig2">
												<strong>图 2. XDoclet 的解析的 Java 源代码的内部结构模型</strong>
										</a>
										<br />
										<img height="395" alt="图 2" src="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/fig2.gif" width="382" />
										<br />
										<p>图 2 中的结构模型跟踪类、接口、方法之类的代码构造（模型元素）。该模型还跟踪元素之间的关系，例如继承和接口实现。以内联注释的形式嵌入在源代码中的 XDoclet 标签被解析为模型元素的属性，并被跟踪。</p>
										<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
												<tbody>
														<tr>
																<td width="10">
																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
																</td>
																<td>
																		<table cellspacing="0" cellpadding="5" width="100%" border="1">
																				<tbody>
																						<tr>
																								<td bgcolor="#eeeeee">
																										<a name="genjavadoc">
																												<strong>通用的 Javadoc 引擎</strong>
																										</a>
																										<br />
																										<p>能够理解 Java 代码结构模型的智能代码生成引擎不是什么新概念。实际上，它是 JDK 自带的 Javadoc 工具的运作方式。通过解析带有特殊 Javadoc 标签的 Java 源文件，Javadoc 工具可以为所有 Java 程序的内置结构元素（包括类、接口、字段和方法）生成 HTML 文档。Javadoc 还具有特殊 Java 语言概念方面的知识，例如继承、抽象类、存储类和修饰符。 </p>
																										<p>XDoclet 的诞生，来自这样一个观察：适用于任意代码生成的 Javadoc 的通用版本，在许多编程场合下会极为有用。但是，实际的 Javadoc 源代码不是为通用的代码生成设计的，而只是为了生成 HTML 文档。由于无法重用现有代码，XDoclet 开发小组从头开始重写了引擎，并显著优化了它的性能。 </p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<table cellspacing="0" cellpadding="0" width="100%" border="0">
												<tbody>
														<tr>
																<td>
																		<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
																		<br />
																		<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" cellspacing="0" cellpadding="0" align="right">
												<tbody>
														<tr align="right">
																<td>
																		<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
																		<br />
																		<table cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td valign="center">
																										<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																										<br />
																								</td>
																								<td valign="top" align="right">
																										<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main">
																												<strong>
																														<font color="#996699">回页首</font>
																												</strong>
																										</a>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="inside">
														<span class="atitle">
																<font size="4">深入 XDoclet </font>
														</span>
												</a>
										</p>
										<p>图 3 显示了 XDoclet 的内部结构，揭示了使其运行的功能块。 </p>
										<br />
										<a name="fig3">
												<strong>图 3. XDoclet 内部的功能块</strong>
										</a>
										<br />
										<img height="502" alt="图 3" src="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/fig3.gif" width="544" />
								</td>
						</tr>
				</tbody>
		</table>  
<p>如图 3 所示，Apache Ant 在运行的时候控制着 XDoclet 的配置和操作。XDoclet 解析输入的 Java 源代码，并在内存中生成结构模型。模板引擎通过处理一组模板和标签处理器，生成输出文件。模板和标签处理器可以是内置的，也可以是定制的。在代码生成期间，模板和标签处理器拥有对结构模型的完全访问。 </p><p><a name="1.0"><span class="smalltitle"><strong><font size="3">XDoclet 虚假的复杂性</font></strong></span></a></p><p>XDoclet 实质上就是一个通用的 Javadoc 引擎（请参阅侧栏， <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#genjavadoc"><font color="#996699">通用的 Javadoc 引擎</font></a>）。那么，是什么让它看起来这么复杂呢？答案在于：XDoclet 几乎从未被单独讨论过，而总是藏在其他许多复杂的技术中。图 4 显示了了围绕在 XDoclet 周围的复杂性迷雾（请参阅侧栏 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#genxdoc"><font color="#996699">为什么 XDoclet 看起来比实际的要复杂得多</font></a>）。 </p><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="genxdoc"><strong>为什么 XDoclet 看起来比实际的要复杂得多</strong></a><br /><p>Apache Ant 自动进行 Java 软件的生成过程。构建管理过程通常是生产项目中更复杂过程中的一部分。构建管理的术语和概念被集成到 Apache Ant 中，而且是理解其操作的先决条件。成熟的 Ant 脚本可能会非常复杂。Ant 的每个新版本，都会引入一些新的特性集，从而进一步增加了复杂性。这形成了 XDoclet 表面的复杂性，因为 XDoclet 需要 Ant 才能执行。 </p><p>XDoclet 处理的问题领域是复杂性的另一个来源。在发布 XDoclet 的时候，XDoclet 已经可以为 EJB 组件集成、J2EE Web 容器集成、Hibernate 持久性层、Struts 框架、Java 管理扩展（JMX）等生成代码。这些问题领域中的每一个领域都有一大套该领域专用的行话和概念。从这些复杂的问题领域出来的问题，经常主导着 XDoclet 的讨论，这也提高了 XDoclet 表面的复杂性。可能是“只见森林，不见树木”。 </p></td></tr></tbody></table></td></tr></tbody></table><br /><a name="fig4"><strong>图 4. XDoclet 的复杂耦合</strong></a><br /><img height="477" alt="Figure 4" src="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/fig4.gif" width="517" /><br /><p>在图 4 中，您可以看到 XDoclet 与以下内容是紧密相关的：</p><ul><li>Apache Ant，它控制着 XDoclet 的操作。XDoclet 是作为一组 Ant 任务存在的，没有 Ant 则不能执行。 
</li><li>与生成文件关联的具体问题领域的一些细节。 </li></ul><p>XDoclet 本身却是惊人地简单，正如下面示例中的工作代码所示的那样。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main"><strong><font face="Verdana" color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="workwith"><span class="atitle"><strong><font size="4">使用 XDoclet </font></strong></span></a></p><p>现在，您可以通过研究我向您提供的数据入口应用程序示例，来观察 XDoclet 的实际工作。（要下载这个示例中使用的 Java 代码、XDoclet 模板和 Ant 脚本，请单击本文顶部或底部的 <strong>Code</strong>图标，或者请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#download"><font color="#996699">下载部分</font></a>。）我们将从检查清单 1 所示的 Java 代码开始，这部分代码表示了一个客户的地址。该地址被编码成 JavaBean 组件，其中的 XDoclet 标签是以黑体字形式显示的： </p><br /><a name="list1"><strong>清单 1. 用 XDoclet 标签标记的 AddressBean.java 源文件 </strong></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package com.ibm.dw.beans;import java.io.Serializable;/**        </font><span class="boldcode"><strong><font face="Lucida Console" size="2">* @dw.genStrutsAction action="/addAddress.do"* @hibernate.class table="ADDRESS"</font></strong></span><font face="Lucida Console">*/public class AddressBean implements Serializable {private String streetNumber = "";private String street = "";private String city = "";private String country = "";private String postalCode = "";private long id = 0;public AddressBean() {}/**        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">* @dw.genStruts formlabel="Street Number"* @hibernate.property length="10"</font></strong></span>*/public String getStreetNumber() {   return streetNumber;}public void setStreetNumber(String inpStreetNumber) {   streetNumber = inpStreetNumber;}/**        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">* @dw.genStruts formlabel="Street"* @hibernate.property  length="40"</font></strong></span>*/public String getStreet() {    return street;}public void setStreet(String inpStreet) {   street = inpStreet;}        <span class="boldcode"><strong><font size="2">...... more Address bean properties ......</font></strong></span>/**        <span class="boldcode"><strong><font size="2">* @hibernate.id generator-class="native"</font></strong></span>*/public long getId(  ){        return id;}public void setId(long inId) {   id = inId;}}      </font></code></pre></td></tr></tbody></table><br /><p>在清单 1 中，需要注意的是，要把 XDoclet 标签嵌入到注释中，紧放在相关代码元素（例如字段、方法、接口或类）的前面。在解析源代码时，XDoclet 会为每个标签建立一个属性，并将该属性附加到结构模型的代码元素上。现在，请注意 <code><font face="Courier" size="2">@dw.genStruts</font></code> 标签，因为这是在本例中将用到的第一个模板。 </p><p><a name="genjava"><span class="smalltitle"><strong><font size="3">生成另外一个 Java 类 </font></strong></span></a></p><p>对于本例，您需要生成新的 Java 类的代码 —— 一个 Struts 表单 bean。Struts 会用这个 bean 保存并传输用户输入。bean 必须以 bean 属性的形式包含所有数据字段，而且它必须是 <code><font face="Courier" size="2">org.apache.struts.action.ActionForm</font></code> 的子类。 </p><p>为了生成表单 bean 的代码，您要根据清单 2 所示的伪代码生成 XDoclet 模板。括号中的黑体字代表控制流逻辑和您要进行替换的文本。请注意模板是如何从已解析的 Java 源代码文件的结构模型中提取信息的： </p><br /><a name="list2"><strong>清单 2. 建立 AddressBeanForm.java Struts 表单 bean 代码的伪代码模板 </strong></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package         <span class="boldcode"><strong><font size="2">{package name of source class}</font></strong></span>;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;import org.apache.struts.upload.FormFile;/** * Form Bean class for         <span class="boldcode"><strong><font size="2">{name of source class}</font></strong></span>;. * * @struts.form name="        <span class="boldcode"><strong><font size="2">{name of source class}</font></strong></span>Form" */public class         <span class="boldcode"><strong><font size="2">{name of source class}</font></strong></span>Form extends ActionForm {        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">{loop through all the methods in the source class}   {if the method is a JavaBean "getter" method}      {if the method has been marked with the @dw.genStruts tag }</font></strong></span>	private         <span class="boldcode"><strong><font size="2">{return type of method}</font></strong></span><span class="boldcode"><strong><font size="2">{name of the JavaBean property}</font></strong></span>; 	public         <span class="boldcode"><strong><font size="2">{return type of method}</font></strong></span><span class="boldcode"><strong><font size="2">{name of the getter method for this property}</font></strong></span>(){		return         <span class="boldcode"><strong><font size="2">{name of JavaBean property}</font></strong></span>;	}	public void         <span class="boldcode"><strong><font size="2">{name of the setter method for this property}</font></strong></span>(	                                    <span class="boldcode"><strong><font size="2">{return type of method}</font></strong></span> value) {                    <span class="boldcode"><strong><font size="2">{name of the JavaBean property}</font></strong></span> = value;      			}               </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">{end of if @dw.genStruts}    {end of if JavaBean getter}{end of loop}</font></strong></span></font></code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><font face="Lucida Console"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></font></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="genxdoc"><strong>用 XDoclet 建立 XDoclet 标签</strong></a><br /><p>请注意在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#list2"><font color="#996699">清单 2</font></a> 的模板中生成的 XDoclet <code><font face="Courier" size="2">@struts.form</font></code> 标签。您可以用 XDoclet 在 Java 源代码中生成 XDoclet 标签，XDoclet 会在后面的操作中再次处理这些标签。在示例后面建立 structs-config.xml 的时候，XDoclet 会使用 <code><font face="Courier" size="2">@struts.form</font></code> 标签。 </p></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p>在清单 2 的循环中的代码生成了一个字段声明和一个访问器方法，还为输入源代码中每个用 <code><font face="Courier" size="2">@dw.genStruts</font></code> 标记的访问器方法生成了一个设置器方法。 </p><p>清单 2 使用了易于理解的伪代码来表示模板替换标签。实际的 XDoclet 模板标签则相当繁琐。清单 3 显示了 genformbean.xdt 模板（所有的 XDoclet 模板都保存在 .xdt 文件中）。我已经用黑体字强调了 XDoclet 模板标签，以方便在伪代码中对其进行引用。 </p><br /><a name="list3"><strong>清单 3. 建立 Structs 表单 bean Java 代码的实际 XDoclet 模板代码 </strong></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package         <span class="boldcode"><strong><font size="2">&lt;XDtPackage:packageName/&gt;</font></strong></span>;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;import org.apache.struts.upload.FormFile;/** * Form Bean class for         <span class="boldcode"><strong><font size="2">&lt;XDtClass:className/&gt;</font></strong></span>. * * @struts.form name="        <span class="boldcode"><strong><font size="2">&lt;XDtClass:className/&gt;</font></strong></span>Form" */public class         <span class="boldcode"><strong><font size="2">&lt;XDtClass:className/&gt;</font></strong></span>Form extends ActionForm {        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;XDtMethod:forAllMethods&gt;   &lt;XDtMethod:ifIsGetter&gt;      &lt;XDtMethod:ifHasMethodTag tagName="dw.genStruts"&gt;</font></strong></span>	private         <span class="boldcode"><strong><font size="2">&lt;XDtMethod:methodType/&gt; &lt;XDtMethod:propertyName/&gt;</font></strong></span>; 	public         <span class="boldcode"><strong><font size="2">&lt;XDtMethod:methodType/&gt; &lt;XDtMethod:getterMethod/&gt;</font></strong></span>(){		return         <span class="boldcode"><strong><font size="2">&lt;XDtMethod:propertyName/&gt;</font></strong></span>;	}	public void         <span class="boldcode"><strong><font size="2">&lt;XDtMethod:setterMethod/&gt;</font></strong></span>(        <span class="boldcode"><strong><font size="2">&lt;XDtMethod:methodType/&gt;</font></strong></span> value) {                    <span class="boldcode"><strong><font size="2">&lt;XDtMethod:propertyName/&gt;</font></strong></span> = value;      			}             </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;/XDtMethod:ifHasMethodTag&gt;   &lt;/XDtMethod:ifIsGetter&gt;&lt;/XDtMethod:forAllMethods&gt;</font></strong></span></font></code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><font face="Lucida Console"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></font></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="fluantc"><strong>熟悉 Ant 脚本编写</strong></a><br /><p>Ant 脚本 build.xml（我已经随本文的示例代码提供了这个文件，请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#download"><font color="#996699">下载部分</font></a>找到代码的链接）定义了示例应用程序使用的全部必要 Ant 目标。如果您想修改脚本，就需要熟悉 Ant。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a> 了解 Ant 的更多信息。 </p></td></tr></tbody></table></td></tr></tbody></table><p>您可以参考 XDoclet 的“模板语言”文档，查找 XDoclet 所有可用标签的列表（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a>）。 </p><p>要运行用于 AddressBean.java 源文件的模板，请使用以下 Ant 命令行：</p><table cellspacing="0" cellpadding="5" width="600" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">ant -Dbase.class.java=Address genstruts</font></code></pre></td></tr></tbody></table><br /><p>这个命令可以执行定制 Ant 目标（请参阅侧栏 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#fluent"><font color="#996699">熟悉 Ant 脚本编写</font></a>）来处理 genbeanform.xdt 模板。XDoclet 提供的 Ant 任务叫作 <code><font face="Courier" size="2">xdoclet.DocletTask</font></code> ，它被用来运行模板文件。如果您对 Ant 的细节感兴趣，请参阅示例代码中的 build.xml 文件，以了解更多信息。 </p><p>在 XDoclet 处理模板的时候，它在名为 <em>generated</em>的子目录下生成一个 AddressBeanForm.java 文件。清单 4 显示了该文件，它包含模板处理期间替换的所有文本： </p><br /><a name="list4"><strong>清单 4. XDoclet 生成的包含 Struts 表单 bean 的 Java 源代码</strong></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">package         <span class="boldcode"><strong><font size="2">com.ibm.dw.beans</font></strong></span>;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;import org.apache.struts.upload.FormFile;/** * Form Bean class for         <span class="boldcode"><strong><font size="2">AddressBean</font></strong></span>. * * @struts.form name="        <span class="boldcode"><strong><font size="2">AddressBean</font></strong></span>Form" */public class         <span class="boldcode"><strong><font size="2">AddressBean</font></strong></span>Form extends ActionForm {	private         <span class="boldcode"><strong><font size="2">java.lang.String streetNumber</font></strong></span>; 	public         <span class="boldcode"><strong><font size="2">java.lang.String getStreetNumber</font></strong></span>(){		return         <span class="boldcode"><strong><font size="2">streetNumber</font></strong></span>;	}	public void         <span class="boldcode"><strong><font size="2">setStreetNumber</font></strong></span>(        <span class="boldcode"><strong><font size="2">java.lang.String</font></strong></span> value) {                    <span class="boldcode"><strong><font size="2">streetNumber</font></strong></span> = value;      			}	private         <span class="boldcode"><strong><font size="2">java.lang.String</font></strong></span><span class="boldcode"><strong><font size="2">street</font></strong></span>; 	public         <span class="boldcode"><strong><font size="2">java.lang.String getStreet</font></strong></span>(){		return         <span class="boldcode"><strong><font size="2">street</font></strong></span>;	}	public void         <span class="boldcode"><strong><font size="2">setStreet</font></strong></span>(        <span class="boldcode"><strong><font size="2">java.lang.String</font></strong></span> value) {                    <span class="boldcode"><strong><font size="2">street</font></strong></span> = value;      			}           <span class="boldcode"><strong><font size="2">...... more bean properties .....</font></strong></span>}      </font></code></pre></td></tr></tbody></table><br /><p><a name="genjsp"><span class="smalltitle"><strong><font size="3">为数据表单输入生成 JSP 页面</font></strong></span></a></p><p>您可以用相同的 AddressBean.java 源文件，但是用 genformjsp.xdt 模板生成数据入口表单 JSP 页面。清单 5 显示了 genformjsp.xdt： </p><br /><a name="list5"><strong>清单 5. 使用 Struts 标签库生成 JSP 页面来显示 HTML 表单的 XDoclet 模板</strong></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;%@ page language="java" %&gt;&lt;%@ taglib  uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;&lt;html:html&gt;&lt;head&gt;&lt;/head&gt;&lt;body bgcolor="white"&gt;&lt;html:errors/&gt;&lt;html:form action="        <span class="boldcode"><strong><font size="2">&lt;XDtClass:classTagValue tagName='dw.genStrutsAction'  paramName='action' /&gt;</font></strong></span> &gt;"&lt;table border="0" width="100%"&gt;        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;XDtMethod:forAllMethods&gt;   &lt;XDtMethod:ifIsGetter&gt;      &lt;XDtMethod:ifHasMethodTag tagName="dw.genStruts" &gt;</font></strong></span>    &lt;tr&gt;        &lt;th align="right"&gt;                   </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;XDtMethod:methodTagValue                    tagName="dw.genStruts" paramName="formlabel"/&gt;</font></strong></span>        &lt;/th&gt;        &lt;td align="left"&gt;            &lt;html:text  property="        <span class="boldcode"><strong><font size="2">&lt;XDtMethod:propertyName/&gt;</font></strong></span>"              size="        </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;XDtMethod:ifHasMethodTag tagName="hibernate.property" &gt;              &lt;XDtMethod:methodTagValue tagName="hibernate.property" paramName="length"/&gt;              &lt;/XDtMethod:ifHasMethodTag&gt;</font></strong></span>"/&gt;        &lt;/td&gt;    &lt;/tr&gt;             </font><font face="Lucida Console"><span class="boldcode"><strong><font size="2">&lt;/XDtMethod:ifHasMethodTag&gt;   &lt;/XDtMethod:ifIsGetter&gt;&lt;/XDtMethod:forAllMethods&gt;</font></strong></span>    &lt;tr&gt;        &lt;td align="right"&gt;            &lt;html:submit&gt;                Submit            &lt;/html:submit&gt;        &lt;/td&gt;        &lt;td align="left"&gt;            &lt;html:reset&gt;              Reset            &lt;/html:reset&gt;        &lt;/td&gt;    &lt;/tr&gt;&lt;/table&gt;&lt;/html:form&gt;&lt;/body&gt;&lt;/html:html&gt;      </font></code></pre></td></tr></tbody></table><br /><p>请注意，代码中用 <code><font face="Courier" size="2">&lt;XDt:methodTagValue&gt;</font></code> 取得原始 AddressBean.java 代码中在 XDoclet 标签中指定的属性值。 </p><p>当您执行 <code><font face="Courier" size="2">genstruts</font></code> Ant 目标的时候，也会处理清单 5 显示的 genformjsp.xdt 模板。您可以在 <em>generated</em> 子目录中找到生成的 AddressBeanForm.jsp 文件，检查文件内容，可以看到要对模板进行的替换。 </p><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="genxdoc"><strong>试验示例，但是首先...</strong></a><br /><p>要试验本文示例中的模板化代码生成，您需要安装并测试好 Ant 和 XDoclet。本文中的代码全都基于 Ant 1.5.4 和 XDoclet 1.2.1。要生成所有的工件，并试验生成的 Web 应用程序，还需要安装 Hibernate，Struts，以及应用程序服务器，还需要能够访问关系数据库。示例基于 Hibernate 2.1.4，Struts 1.1，以及 Servlet 2.3。请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#resources"><font color="#996699">参考资料</font></a> 了解有关这些技术的更多信息。请一定要阅读我随源代码一起提供的 README 文件。 </p></td></tr></tbody></table></td></tr></tbody></table><p><a name="genjsp"><span class="smalltitle"><strong><font size="3">生成其他工件 </font></strong></span></a></p><p>您可以用 XDoclet 生成任意基于文本的输出。我向您展示的例子使用 XDoclet 生成了 Java 代码、JSP 页面、XML 文件、配置文件以及其他更多输出。它从一个简单的用 XDoclet 进行标记的 Java 源文件 AddressBean.java，建立了一个完整的数据入口 Web 应用程序。为了做到这一点，它执行了 XDoclet 的内置模板（位于 JAR 文件中，称为模块），从而生成：</p><ul><li>Struts 配置和支持文件。 
</li><li>Hibernate 配置和支持文件。 
</li><li>Web 应用程序的部署描述符（web.xml）。 </li></ul><p>表 1 显示了为示例应用程序生成的所有文件（通常称为 <em>工件（artifact）</em>）： </p><br /><a name="table1"><strong>表 1. XDoclet 为 AddressBean.java 生成的工件</strong></a><br /><table cols="3" width="600" border="1"><tbody><tr><td width="150"><strong>生成的工件</strong></td><td width="300"><strong>说明</strong></td><td width="150"><strong>位置</strong></td></tr><tr><td valign="top">AddressBeanForm.java</td><td>Java 源文件，包含表单 bean 类，在 Struts 的表单处理中使用</td><td><em>generated</em>目录 </td></tr><tr><td valign="top">AddressBeanForm.jsp</td><td>JSP 表单，用 Struts 标签库接受用户地址输入</td><td><em>jsp</em>目录 </td></tr><tr><td valign="top">AddressBeanAction.java</td><td>Struts 动作类，接受输入值，用 Hibernate 把值保存到关系数据库</td><td><em>generated</em>目录 </td></tr><tr><td valign="top">AddressBean.hbm.xml</td><td>Hibernate 映射文件，在 <code><font face="Courier" size="2">AddressBean</font></code> Java 对象和数据库的关系型 ADDRESS 表之间进行映射 </td><td><em>web/classes</em>目录 </td></tr><tr><td valign="top">dwschema.sql</td><td>RDBMS 表的架构，用来对 <code><font face="Courier" size="2">AddressBean</font></code> 对象的实例进行持久化 </td><td><em>sql</em>目录 </td></tr><tr><td valign="top">hibernate.cfg.xml</td><td>Hibernate 运行时的配置文件</td><td><em>web/classes</em>目录 </td></tr><tr><td valign="top">web.xml</td><td>生成的 Web 应用程序的部署描述符</td><td><em>web</em>目录 </td></tr><tr><td valign="top">struts-config.xml</td><td>Struts 框架的配置文件</td><td><em>web</em>目录 </td></tr></tbody></table><p>在这篇文章中，您详细了解了表 1 中所列的两个工件中的第一个工件的生成，深入了解了生成它们的模板。工件 AdddressBeanAction.java 则用类似的方法，利用叫作 genaction.xdt 的模板生成。XDoclet 具有内置模板和标签处理器，可以生成表 1 中的其他工件。</p><p>表 2 列出了每个生成的工件对应的 Ant 目标和 Ant 任务。您可以执行表格中的每个 Ant 目标，生成对应的工件。所有这些生成的工件，再加上原始和 AddressBean.java，共同构成了示例 Web 应用程序。您还会发现叫作 <code><font face="Courier" size="2">all</font></code> 的默认 Ant 目标，它会为您做任何事，包括为应用程序建立 WAR（可以部署的 Web 归档）。在进行处理之前，一定要阅读代码发布包中的 README.txt 文件。 </p><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="genxdoc"><strong>XDoclet 中的合并点 </strong></a><br /><p>在 XDoclet 的文档中，您会非常频繁地看到术语 <em>合并点（merge point）</em>和 <em>合并文件（merge file）</em>。合并文件是文本文件，您可以把它合并到 XDoclet 生成代码的指定位置——“合并点”上（由模板指定）。可以用合并文件来包含静态文本（例如代码片断和 XML 片断），这些文本可能很难或者不能用 XDoclet 的能力生成。例如，在示例代码的 <em>merge/web</em> 目录下，您会找到 struts-action.xml 文件。在代码生成期间，可以用该文件合并到 Struts 的动作映射中，构成生成的 struts-config.xml 文件的一部分。 </p></td></tr></tbody></table></td></tr></tbody></table><br /><a name="table2"><strong>表 2. 对应于生成工件的 Ant 目录和 Ant 任务</strong></a><br /><table cols="2" width="600" border="1"><tbody><tr><td><strong>Ant 目标</strong></td><td width="150"><strong>Ant 任务</strong></td><td width="300"><strong>工件</strong></td></tr><tr><td valign="top"><code><font face="Courier" size="2">genstruts</font></code></td><td valign="top" width="150"><code><font face="Courier" size="2">xdoclet.DocletTask</font></code></td><td>AddressBeanForm.java</td></tr><tr><td valign="top"><code><font face="Courier" size="2">genstruts</font></code></td><td valign="top"><code><font face="Courier" size="2">xdoclet.DocletTask</font></code></td><td>AddressBeanForm.jsp</td></tr><tr><td valign="top"><code><font face="Courier" size="2">genstruts</font></code></td><td valign="top"><code><font face="Courier" size="2">xdoclet.DocletTask</font></code></td><td>AddressBeanAction.java</td></tr><tr><td valign="top"><code><font face="Courier" size="2">generateHIB</font></code></td><td valign="top"><code><font face="Courier" size="2">xdoclet.modules.hibernate.HibernateDocletTask</font></code></td><td>AddressBean.hbm.xml</td></tr><tr><td valign="top"><code><font face="Courier" size="2">generateHIB</font></code></td><td valign="top" width="150"><code><font face="Courier" size="2">xdoclet.modules.hibernate.HibernateDocletTask</font></code></td><td>hibernate.cfg.xml</td></tr><tr><td valign="top"><code><font face="Courier" size="2">createDDL</font></code></td><td valign="top" width="150"><code><font face="Courier" size="2">xdoclet.modules.hibernate.HibernateDocletTask</font></code></td><td>dwschema.sql</td></tr><tr><td valign="top"><code><font face="Courier" size="2">generateDD</font></code></td><td valign="top" width="150"><code><font face="Courier" size="2">xdoclet.modules.web.WebDocletTask</font></code></td><td>web.xml</td></tr><tr><td valign="top"><code><font face="Courier" size="2">generateDD</font></code></td><td valign="top" width="150"><code><font face="Courier" size="2">xdoclet.modules.web.WebDocletTask</font></code></td><td>struts-config.xml</td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main"><strong><font face="Verdana" color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="conclusion"><span class="atitle"><strong><font size="4">结束语</font></strong></span></a></p><p>XDoclet 是一个有用的、智能的代码生成器，您可以用它自动进行许多日常的 Java 开发任务。不要被它表面的复杂所吓退。随着逐渐精通 XDoclet（以及与之相关的 Apache Ant），您会节约您宝贵的时间，并在未来的开发工作中，得到数倍的回报。 </p><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main"><strong><font face="Verdana" color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><span class="atitle"><a name="download"><strong><font size="4">下载</font></strong></a></span></p><table class="data-table-1" cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><th>名字</th><th style="TEXT-ALIGN: right">大小</th><th>下载方法</th></tr><tr><td nowrap="">j-xdoclet-code.zip</td><td style="TEXT-ALIGN: right" nowrap=""> </td><td nowrap=""> <a class="fbox" href="ftp://www6.software.ibm.com/software/developer/library/j-xdoclet-code.zip"><strong><font face="Verdana" color="#5c81a7">FTP</font></strong></a></td></tr></tbody></table><table cellspacing="0" cellpadding="0" border="0"><tbody><tr valign="top"><td colspan="5"><font face="Verdana" color="#5c81a7"><img height="12" alt="" src="http://www.ibm.com/i/c.gif" width="12" border="0" /></font></td></tr><tr><td><font face="Verdana" color="#5c81a7"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/fw.gif" width="16" /></font></td><td><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/whichmethod.html"><font face="Verdana" color="#5c81a7">关于下载方法的信息</font></a></td><td><font face="Verdana" color="#5c81a7"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="50" /></font></td><td><font face="Verdana" color="#5c81a7"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/sout.gif" width="16" /></font></td><td><a class="fbox" href="http://www.adobe.com/products/acrobat/readstep2.html"><font face="Verdana" color="#5c81a7">Get Adobe® Reader®</font></a></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Verdana" color="#5c81a7"><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Verdana" color="#5c81a7"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Verdana" color="#5c81a7"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main"><strong><font face="Verdana" color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><strong><font size="4">参考资料 </font></strong></span></a></p><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-xdoclet/" target="_blank"><font color="#5c81a7">英文原文</font></a>。 <br /><br /></li><li>单击这篇文章顶部或底部的 <strong>Code</strong>图标（或者参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#download"><font color="#996699">下载部分</font></a>），下载本例中用到的 Java 代码、XDoclet 模板和 Ant 脚本。 <br /><br /></li><li>在官方的开放源代码站点上，了解更多有关 <a href="http://xdoclet.sourceforge.net/xdoclet/index.html"><font color="#996699">XDoclet</font></a>的内容，上面提供了最新的源代码、下载、文档、FAQ 和邮件列表。 <br /><br /></li><li>下载最新版本的 <a href="http://ant.apache.org/"><font color="#5c81a7">Apache Ant</font></a>生成管理和自动化工作。 <br /><br /></li><li>访问官方的 <a href="http://www.hibernate.org/"><font color="#5c81a7">Hibernate</font></a>站点，得到最新版本的 Hibernate 持久性层、文档、邮件列表和社区新闻。 <br /><br /></li><li>参阅最新版本的 <a href="http://struts.apache.org/"><font color="#5c81a7">Struts</font></a>MVC 框架。 <br /><br /></li><li>“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-santa1/index.html"><font color="#5c81a7">编写自己的 secret Santa Web 应用程序，第 1 部分：bean</font></a>”（ <em>developerWorks</em>，2003 年 12 月）展示了 XDoclet 可以怎样加速 J2EE 应用程序的开发和部署。 <br /><br /></li><li>教程“ <a href="http://www.ibm.com/developerworks/edu/ws-dw-ws-xdoc-i.html?S_TACT=104AHW02"><font color="#5c81a7">Use XDoclet to generate Web service support files</font></a>”（ <em>developerWorks</em>, 2003 年 6月） 向 J2EE 开发人员展示了如何用 XDoclet 来编写自己的定制模板和子任务。 <br /><br /></li><li>教程“ <a href="http://www.ibm.com/developerworks/edu/ws-dw-ws-j2x-i.html?S_TACT=104AHW02"><font color="#5c81a7">Enhance J2EE component reuse with XDoclet</font></a>”（ <em>developerWorks</em>, 2003 年 5 月） 向 J2EE 开发人员展示了如何用 XDoclet 来提高开发速度。 <br /><br /></li><li>要为本文的示例使用一个开放源代码的应用程序服务，可以尝试 <a href="http://jakarta.apache.org/tomcat/index.html"><font color="#5c81a7">Tomcat 5</font></a>服务器。 <br /><br /></li><li>探索另外一个易于使用的模板语言，请参阅 Sing Li 的文章“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-velocity/index.html"><font color="#5c81a7">使用 Velocity 实现客户端和服务器端模板</font></a>”（ <em>developerWorks</em>，2004 年 2 月）。 <br /><br /></li><li><a href="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=1932394052"><font color="#5c81a7"><em>XDoclet in Action</em></font></a>（Independent Pub Group; 2003）的作者是 Walls 和 Richards，它是 XDoclet 代码生成的完整资源。 <br /><br /></li><li>学习 Java 5 中新的元数据功能，请参阅“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-annotate1/index.html"><font color="#5c81a7">Tiger 中的注释，第 1 部分: 向 Java 代码中添加元数据</font></a>”和“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-annotate2/index.html"><font color="#5c81a7">Tiger 中的注释，第 2 部分: 定制注释</font></a>"（ <em>developerWorks</em>，2004 年 9 月）。 <br /><br /></li><li>在 <em>developerWorks</em><a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7">Java 技术专区</font></a>中，可以找到数百篇 Java 技术资源。 <br /><br /></li><li>请访问 <a href="http://devworks.krcinfo.com/"><font color="#5c81a7">Developer Bookstore</font></a>，以获得技术书籍的完整列表，其中包括数百本 <a href="http://devworks.krcinfo.com/WebForms/ProductList.aspx?Search=Category&amp;id=1200"><font color="#5c81a7">Java 相关主题</font></a>的书籍。 <br /></li></ul><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /><img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-xdoclet/index.html#main"><strong><font face="Verdana" color="#996699">回页首</font></strong></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="author"><span class="atitle"><strong><font size="4">关于作者</font></strong></span></a></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td colspan="3"><strong><font size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /></font></strong></td></tr><tr valign="top" align="left"><td><p><strong><font size="4"><img height="80" alt="Author photo" src="http://www.ibm.com/developerworks/i/p-sing.jpg" width="64" align="left" /></font></strong></p></td><td><strong><font size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /></font></strong></td><td width="100%"><p>Sing Li 是 <a href="http://www.wrox.com/books/0764559028.shtml"><font color="#5c81a7"><em>Professional Apache Tomcat 5</em></font></a>、 <a href="http://www.apress.com/book/bookDisplay.html?bID=256"><font color="#5c81a7"><em>Pro JSP, Third Edition</em></font></a>、 <em>Early Adopter JXTA</em>、 <em>Professional Jini</em>，以及 Wrox Press 出版的许多其他图书的作者。他是技术杂志的定期撰稿人，还是 P2P 发展的热心传播者。Sing 是一名咨询顾问和资深作者，您可以通过他的电子邮件 <a href="mailto:westmakaha@yahoo.com"><font color="#5c81a7">westmakaha@yahoo.com</font></a>与他联系。 </p></td></tr></tbody></table><br /><img src ="http://www.blogjava.net/xzclog/aggbug/79153.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:30 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79153.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Xdoclet学习笔记(XDoclet 如何工作) </title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79152.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:29:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79152.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79152.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79152.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79152.html</trackback:ping><description><![CDATA[
		<p>
				<a name="inside">
						<span class="atitle3">XDoclet 操作</span>
				</a>
				<br />图 1 显示了 XDoclet 要求的输入和生成的输出。 </p>
		<p>
				<a name="fig1">
						<b>图 1. XDoclet 黑盒子</b>
				</a>
				<br />
				<img height="549" alt="图 1" src="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/fig1.gif" width="429" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
		</p>
		<p>您可以看到，包含嵌入式 XDoclet 标签的 Java 源代码是系统的输入。在 Apache Ant 的驱动下，XDoclet 处理输入的代码，生成的输出文本文件可以是 Java 源代码、HTML 页面、XML 文件等。为了处理输入，XDoclet 需要使用模板（保存在 .xdt 文件中）和标签处理器（用 Java 编码）。XDoclet 把模板和标签处理器打包成“模块”，不同的“模块”处理不同的问题域。</p>
		<p>
				<a name="1.0">
						<span class="atitle3">XDoclet 生成的结构模型 </span>
				</a>
				<br />XDoclet 对包含嵌入式 XDoclet 标签的输入 Java 源代码进行解析，并为代码建立非常详细的结构模型。结构模型中的每个元素都代表源代码中的一个 Java 结构。图 2 显示的结构模型，揭示了 XDoclet 跟踪的代码构造和关系。 </p>
		<p>
				<a name="fig2">
						<b>图 2. XDoclet 的解析的 Java 源代码的内部结构模型</b>
				</a>
				<br />
				<img height="395" alt="图 2" src="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/fig2.gif" width="382" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
		</p>
		<p>图 2 中的结构模型跟踪类、接口、方法之类的代码构造（模型元素）。该模型还跟踪元素之间的关系，例如继承和接口实现。以内联注释的形式嵌入在源代码中的 XDoclet 标签被解析为模型元素的属性，并被跟踪</p>
		<p>
		</p>
		<p>
				<a name="inside">
						<span class="atitle2">深入 XDoclet </span>
				</a>
				<br />图 3 显示了 XDoclet 的内部结构，揭示了使其运行的功能块。 </p>
		<p>
				<a name="fig3">
						<b>图 3. XDoclet 内部的功能块</b>
				</a>
				<br />
				<img height="502" alt="图 3" src="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/fig3.gif" width="544" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
		</p>
		<p>如图 3 所示，Apache Ant 在运行的时候控制着 XDoclet 的配置和操作。XDoclet 解析输入的 Java 源代码，并在内存中生成结构模型。模板引擎通过处理一组模板和标签处理器，生成输出文件。模板和标签处理器可以是内置的，也可以是定制的。在代码生成期间，模板和标签处理器拥有对结构模型的完全访问。 </p>
		<p>
		</p>
		<p>
				<a name="1.0">
						<span class="atitle3">XDoclet 虚假的复杂性</span>
				</a>
				<br />XDoclet 实质上就是一个通用的 Javadoc 引擎（请参阅侧栏，<a href="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/index.shtml?ca=dwcn-newsletter-java#genjavadoc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">通用的 Javadoc 引擎</a>）。那么，是什么让它看起来这么复杂呢？答案在于：XDoclet 几乎从未被单独讨论过，而总是藏在其他许多复杂的技术中。图 4 显示了了围绕在 XDoclet 周围的复杂性迷雾（请参阅侧栏<a href="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/index.shtml?ca=dwcn-newsletter-java#genxdoc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">为什么 XDoclet 看起来比实际的要复杂得多</a>）。 </p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="5" width="30%" align="right" border="1">
				<tbody>
						<tr>
								<td background="/developerworks/cn/i/bg-gold.gif">
										<p>
												<a name="genxdoc">
														<b>为什么 XDoclet 看起来比实际的要复杂得多</b>
												</a>
												<br />Apache Ant 自动进行 Java 软件的生成过程。构建管理过程通常是生产项目中更复杂过程中的一部分。构建管理的术语和概念被集成到 Apache Ant 中，而且是理解其操作的先决条件。成熟的 Ant 脚本可能会非常复杂。Ant 的每个新版本，都会引入一些新的特性集，从而进一步增加了复杂性。这形成了 XDoclet 表面的复杂性，因为 XDoclet 需要 Ant 才能执行。 </p>
										<p>XDoclet 处理的问题领域是复杂性的另一个来源。在发布 XDoclet 的时候，XDoclet 已经可以为 EJB 组件集成、J2EE Web 容器集成、Hibernate 持久性层、Struts 框架、Java 管理扩展（JMX）等生成代码。这些问题领域中的每一个领域都有一大套该领域专用的行话和概念。从这些复杂的问题领域出来的问题，经常主导着 XDoclet 的讨论，这也提高了 XDoclet 表面的复杂性。可能是“只见森林，不见树木”。 </p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="fig4">
						<b>图 4. XDoclet 的复杂耦合</b>
				</a>
				<br />
				<img height="477" alt="Figure 4" src="http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/fig4.gif" width="517" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
		</p>
		<p>在图 4 中，您可以看到 XDoclet 与以下内容是紧密相关的：</p>
		<ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
				<li>Apache Ant，它控制着 XDoclet 的操作。XDoclet 是作为一组 Ant 任务存在的，没有 Ant 则不能执行。 
</li>
				<li>与生成文件关联的具体问题领域的一些细节。</li>
		</ul>
<img src ="http://www.blogjava.net/xzclog/aggbug/79152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:29 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《XDoclet in Action》部分章节中文版</title><link>http://www.blogjava.net/xzclog/archive/2006/11/05/79151.html</link><dc:creator>xzc</dc:creator><author>xzc</author><pubDate>Sun, 05 Nov 2006 00:26:00 GMT</pubDate><guid>http://www.blogjava.net/xzclog/archive/2006/11/05/79151.html</guid><wfw:comment>http://www.blogjava.net/xzclog/comments/79151.html</wfw:comment><comments>http://www.blogjava.net/xzclog/archive/2006/11/05/79151.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xzclog/comments/commentRss/79151.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xzclog/services/trackbacks/79151.html</trackback:ping><description><![CDATA[XDoclet起步<br /><br />XDoclet是一个代码生成工具，它可以把你从Java开发过程中繁重的重复劳动中解脱出来。XDoclet可以让你的应用系统开发的更加快速，而你只要付比原先更少的努力。你可以把你手头上的冗长而又必需的代码交给它帮你完成，你可以逃脱“deployment descriptor地狱”，你还可以使你的应用系统更加易于管理。而你所要做的，只不过是在你的注释里，多加一些类javadoc属性。然后，你会惊讶于XDoclet为了做到的一切。<br />讨论XDoclet，有一点比较容易产生混淆，那就是XDoclet不但是一系统的代码生成应用程序，而且它本身还是一个代码生成框架。虽然每个应用系统的细节千变万化（比如EJB代码生成和Struts代码生成是不一样的，而JMX代码生成又是另一番景象），但这些代码生成的核心概念和用法却是类似的。<br />在这一章里，我们将会看到渗透到所有XDoclet代码生成程序当中的XDoclet框架基础概念。但在之前，我们先从一个例子入手。<br /><br />2.1 XDoclet in action<br /><br />每一个程序员都会认识到，他们的程序永远也不会完成。总会有另一些的功能需要添加，另一些的BUG需要修正，或者需要不断的进行重构。所以，在代码里添加注释，提醒自己（或者其他的程序员）有哪些任务需要完成已成为一个共识。<br />如何来跟踪这些任务是否完成了呢？理想情况下，你会收集整理出来一个TODO任务列表。在这方面，XDoclet提供了一个强大的TODO生成器，来帮助你完成这个任务。这是一个把XDoclet引入项目的好机会。<br />2.1.1 一个公共的任务<br />假设你正在开发一个使用了勺子的类。<br />public class Matrix {<br />　　// TODO ? 需要处理当没有勺子的情况<br />　　public void reload() {<br />　　　　// ...<br />　　　　Spoon spoon = getSpoon();<br />　　　　// ...<br />　　}<br />}<br />理想情况下，你在下一次阅读这段代码的时候，你会处理这个“空勺子”(null spoon)的问题。但如果你过了很久才回来看这段代码，你还会记得在这个类里还有一些工作要做吗？当然，你可以在你的源码里全局搜索TODO，甚至你的集成开发环境有一个内建的TODO列表支持。但如果你想把任务所在的类和方法也标注出来的话，XDoclet可以是另一种选择。XDoclet可以为你的项目生成一个TODO报表。<br /><br />2.1.2 添加XDoclet标签<br />为了把你的TODO项目转换成另一种更加正式的格式，你需要对代码进行一些细微的改动。如下所示：<br />public class Matrix {<br />　　/** @todo 需要处理当没有勺子的情况 */<br />　　public void reload() {<br />　　　　// ...<br />　　}<br />}<br />这里加入了一个XDoclet需要的类javadoc标签。XDoclet会使用这些标签标记的信息，以及在这种情况下标签所处的类和方法，来生成TODO报表。<br /><br />2.1.3 与Ant集成<br />要生成TODO报表，你需要确保在你的机器上正确安装了XDoclet。<br />在Ant任务里，最少要包含一个目标（例如init目标）定义&lt;documentdoclet&gt;任务，这是一个Ant自定义任务，例如：<br />　　&lt;taskdef name=”documentdoclet”<br />　　　　classname=”xdoclet.modules.doc.DocumentDocletTask”<br />　　　　classname=”xdoclet.lib.path” /&gt;<br />这个&lt;documentdoclet&gt;任务是XDoclet核心代码生成应用程序中的一个。<br />现在，你可以在Ant构建文件中加入一个todo目标调用这个任务来生成TODO报表，如：<br />　　&lt;target name=”todo” depends=”init”&gt;<br />　　　　&lt;documentdoclet destdir=”todo”&gt;<br />　　　　　　&lt;fileset dir=”${dir.src}”&gt;<br />　　　　　　　　&lt;include name=”**/*.java” /&gt;<br />　　　　　　&lt;/fileset&gt;<br />　　　　　　&lt;info/&gt;<br />　　　　&lt;/documentdoclet&gt;<br />　　&lt;/target&gt;<br />&lt;info&gt;子任务会遍历你的源文件，查找todo标签，并在todo子目录下生成HTML格式的TODO报表。<br /><br />2.1.4 创建一个更加职业化的TODO报表<br />XDoclet生成的TODO报表可以有一个更加职业化的外表。报表会列出一个概览，显示在哪个包哪个类里有todo项（以及todo项的个数）。Todo项可以跟在方法、类和域上，从报表上可以清楚的区别它们。类级别的todo项会标注class，方法级别的todo项会在方法签名上标注M。构造函数和域相关的todo项也会进行相似的标注。<br />这个任务看起来很简单，但考虑到你所需要做的只是在注释上添加一些格式化的@todo标签，相对于那种只有人才可以理解的无格式的松散的注释，这种标签是机器可读的，也更容易编程处理。生成的输出也更容易阅读并且更加的商业化。<br /><br />2.2 任务和子任务<br />生成todo报表，只是XDoclet可以完成的事情当中的冰山一角。当初，XDoclet因为可以自动生成EJB繁杂的接口和布署描述文件而声名鹊起。然而，现在的XDoclet已经发展成了一个全功能的、面向属性的代码生成框架。J2EE代码生成只是XDoclet的一个应用方面，它可以完成的任务已经远远超越了J2EE和项目文档的生成。<br /><br />2.2.1 XDoclet 任务<br />到现在为止，我们一直在讨论使用XDoclet生成代码，但事实上，更确切的说法应该是，我们使用XDoclet的一个特定的任务来生成代码，比如&lt;ejbdoclet&gt;。每一个XDoclet任务关注于一个特定的领域，并提供这个领域的丰富的代码生成工具。<br />[定义：任务（Tasks）是XDoclet里可用的代码生成应用程序的高层概念。]<br />在XDoclet里，目前已有如下所示的七个核心任务。<br />&lt;ejbdoclet&gt;：面向EJB领域，生成EJB、工具类和布署描述符。<br />&lt;webdoclet&gt;：面向Web开发，生成serlvet、自定义标签库和web框架文件。<br />&lt;hibernatedoclet&gt;：Hibernate持续，配置文件、Mbeans<br />&lt;jdodoclet&gt;：JDO，元数据，vender configuration<br />&lt;jmxdoclet&gt;：JMX，MBean接口，mlets，配置文件。<br />&lt;doclet&gt;：使用用户自定义模板来生成代码。<br />&lt;documentdoclet&gt;：生成项目文件（例如todo列报表）<br />这其中，&lt;ejbdoclet&gt;最常用，并且很多项目也仅仅使用XDoclet来进行EJB代码生成。&lt;webdoclet&gt;是其次一个常用的代码生成任务。当然，在一个项目中同时使用几个XDoclet任务是可能的（并且也是推荐的），但在这些任务之间是完全独立的，它们彼此之间并不能进行直接的交流。<br /><br />2.2.2 XDoclet子任务<br />XDoclet的任务是领域相关的，而在某个特定领域的XDoclet任务，又由许许多多紧密耦合在一起的子任务组成的，这些子任务每个都仅仅执行一个非常特定和简单的代码生成任务。<br />[定义：子任务（subtasks）是由任务提供的单目标的代码生成过程]<br />任务提供子任务执行时的上下文，并且把这些相关的子任务组织管理了起来。任务会依赖这些子任务来生成代码。在一个任务当中调用多个子任务来协同完成各种各样比较大型的代码生成任务是非常常见的。比如，在开发EJB时，你可能想要为每一个bean生成一个home接口，一个remote接口以及ejb-jar.xml布署描述符文件。这就是在&lt;ejbdoclet&gt;任务的上下文环境中的三个独立的代码生成子任务。<br />子任务可以随意的组合排列，以满足项目代码生成的需要。某个XDoclet任务包含的子任务经常会共享功能和在源文件中使用相同的XDoclet标签。这意味着当你开始一个任务的时候，你可以很容易的集成进一个相关的子任务，而不需要很大的改动。<br /><br />子任务交互<br />让我们以&lt;ejbdoclet&gt;任务为例，看一下相关的子任务之间是如何进行关联的。假设你正在开发一个CMP（容器管理持久化）实体Bean。你想要使用一些&lt;ejbdoclet&gt;的子任务：<br />•&lt;deploymentdescriptor&gt;：生成ejb-jar.xml布署描述符文件。<br />•&lt;localhomeinterface&gt;：生成local home接口。<br />•&lt;localinterface&gt;：生成local接口。<br />在执行如上子任务的时候，你需要标记出你的实体Bean的CMP域。当你发布你的bean的时候，你还需要在开发商相关的布署描述符中提供某个特定的关系数据库中的特定表和列与你的CMP实体Bean的映射关系。XDoclet可以让你在原先已存在的CMP XDoclet属性基础上再加上一些关系映射属性，然后，你就可以在任务中加入一个开发商相关的子任务（例如&lt;jboss&gt;或者&lt;weblogic&gt;）来生成布署描述符文件。XDoclet提供了几乎所有的应用服务器的支持，你只需要一些初始化的小改动，就可以进行这些应用服务器相关的代码生成了。<br />但那只是冰山一角。你还可以使用&lt;entitycmp&gt;子任务为为你的bean生成一个实体bean接口的实现子类。如果你使用&lt;valueobject&gt;子任务来为了你的bean生成值对象，&lt;entityemp&gt;子任务还会为你的值对象生成方法的实现代码。<br />觉得不可思议了吧。可惜XDoclet没有提供&lt;cupofcoffee&gt;子任务，要不然我们可以喝杯咖啡，休息一下啦。<br />这里不是想向你介绍&lt;ejbdoclet&gt;所有的子任务或者&lt;ejbdoclet&gt;可以完成的所有代码生成功能，而仅仅是想向你展示一下任务的子任务之间是如何工作在一起的。一旦你开始并熟悉了一个XDoclet 子任务，熟悉另一个子任务会变得非常简单- 那种每个子任务都是孤立的相比，使用这种可以相互协作的子任务，开发成本会显著的降低，效果也更加的立竿见影。 <br /><br />2.3 使用Ant执行任务<br />XDoclet“嫁”给了Ant。XDoclet任务就是Ant的自定义任务，除此以外，没有其他运行XDoclet任务的方法。所幸的是，Ant已经成为了Java构建工具事实上的标准，所以这不算什么限制。事实上，反过来，XDoclet与Ant的这种“亲密”关系使得XDoclet可以参与到任何Ant构建过程当中去。<br />2.3.1 声明任务<br />XDoclet并没有和Ant一起发布，所以如果你想要使用XDoclet的话，就需要单独的下载和安装。在使用任何一个XDoclet的任务之前，你首先需要在使用Ant的&lt;taskdef&gt;任务来声明它。例如：<br />&lt;taskdef name=”ejbdoclet”<br />　　classname=”xdoclet.modules.ejb.EjbDocletTask”<br />　　classpathref=”xdoclet.lib.path”/&gt;<br />如果你熟悉Ant的话，你就会知道这段代码是告诉Ant加载&lt;ejbdoclet&gt;的任务定义。当然，你也可以以你喜欢的任何方式来命名这个自定义任务，但最好还是遵守标准的命名规律以免发生混淆。classname和classpathref属性告诉Ant到哪里去找实现这个自定义任务的XDoclet类。如果你想使用其他的XDoclet任务，就必须要类似这样首先声明这个任务。<br />一般共通的做法是，把所有需要使用的XDoclet任务都放在Ant的一个目标里声明，这样在其他的目标里如果需要使用这些任务，只要depends这个任务就可以了。你可能已经在Ant的构建文件里包含了init目标，这就是放置XDoclet任务声明的好地方（当然如果你没有，你也可以建一个）。下面的例子就是在一个init目标里加入了&lt;ejbdoclet&gt;和&lt;webdoclet&gt;的声明：<br />&lt;target name=”init”&gt;<br />　　&lt;taskdef name=”documentdoclet”<br />　　　　classname=”xdoclet.modules.doc.DocumentDocletTask”<br />　　　　classpathref=”xdoclet.lib.path” /&gt;<br />　　　　&lt;taskdef name=”ejbdoclet”<br />　　　　　　classname=”xdoclet.modules.ejb.EjbDocletTask”<br />　　　　　　classpathref=”xdoclet.lib.path” /&gt;<br />　　　　&lt;taskdef name=”webdoclet”<br />　　　　　　classname=”xdoclet.modules.web.WebDocletTask”<br />　　　　　　classpathref=”xdoclet.lib.path” /&gt;<br />&lt;/target&gt;<br />现在，任务声明好了，XDoclet“整装待发”。<br /><br />2.3.2 使用任务<br />你可以在任何目标里使用声明好的任务。在任务的上下文环境里，可以调动相关的子任务。让我们看一个例子，这个例子调用了&lt;ejbdoclet&gt;任务。不要担心看不懂语法的细节，现在你只需要关心一些基础概念就可以了。<br />&lt;target name=”generateEjb” depends=”init”&gt;<br />　　&lt;ejbdoclet destdir=”${gen.src.dir}”&gt;<br />　　　　&lt;fileset dir=”${src.dir}”&gt;<br />　　　　　　&lt;include name=”**/*Bean.java”/&gt;<br />　　　　&lt;/fileset&gt;<br />　　&lt;deploymentdescriptor destdir=”${ejb.deployment.dir}”/&gt;<br />　　&lt;homeinterface/&gt;<br />　　&lt;remoteinterface/&gt;<br />　　&lt;localinterface/&gt;<br />　　　&lt;localhomeinterface/&gt;<br />　　&lt;/ejbdoclet&gt;<br />&lt;/target&gt;<br />把任务想像成一个子程序运行时需要的一个配置环境（记住，子任务才是真正进行代码生成工作的）。当调用一个子任务时，子任务从任务继承上下文环境，当然，你也可以根据需要随意的覆盖这些值。在上面的例子里，因为&lt;deploymentdescriptor&gt;子任务生成的布署描述符文件和其他生成各种接口的子任务生成的Java源文件需要放在不同的位置，所以覆盖了destdir的属性值。布署描述符文件需要放在一个在打包EJB JAR文件的时候可以容易包含进来的地方，而生成的Java代码则需要放置在一个可以调用Java编译器进行编译的地方。需要这些子任务之间是紧密关联的，但只要你需要，你可以有足够的自主权控制任务的生成环境。<br />&lt;fileset&gt;属性同样被应用到所有的子任务。这是一个Ant的复杂类型（相对于文本和数值的简单类型），所以以子元素的方式在任务中声明。不要把它和子任务混为一谈。当然，如果你想在某个子任务中另外指定一个不同的输入文件集，你也可以在这个子任务中放置一个&lt;fileset&gt;子元素来覆盖它。<br />子任务的可配置选项远远不止这些。我们会在下一章继续介绍所有的任务和子任务，以及常用的配置选项。<br /><br />2.4 用属性标注你的代码<br />可重用的代码生成系统需要输入来生成感兴趣的输出。一个解析器生成器也需要一个语言描述来解析生成解析器。一个商务对象代码生成器需要领域模型来知道要生成哪些商务对象。XDoclet则需要Java源文件做为输出来生成相关的类或者布署/配置文件。<br />然而，源文件可能并没有提供代码生成所需要的所有信息。考虑一个基于servlet的应用，当你想生成web.xml文件的时候，servlet源文件仅可以提供类名和适当的servlet接口方法。其他的信息比如URI pattern映射、servlet需要的初始化参数等信息并没有涵盖。显而易见，如果class并没有提供这些信息给你，你就需要自己手动在web.xml文件时填写这些信息。<br />XDoclet当然也不会知道这些信息。幸运的是，解决方法很简单。如果所需信息在源文件时没有提供，那就提供它，做法就是在源文件里加入一些XDoclet属性。XDoclet解析源文件，提取这些属性，并把它们传递给模板，模板使用这些信息生成代码。<br /><br />2.4.1 剖析属性<br />XDoclet属性其实就是javadoc的扩展。它们在外表上和使用上都有javadoc属性一样，可以放置在javadoc文档注释里。文档注释以/**开始，*/结尾。下面是一个简单的例子：<br />/**<br />* 这是一段javadoc注释。<br />* 注释可以被分解成多行，每一行都以星号开始。<br />*/<br />在注释里的所有文本都被视为javadoc注释，并且都能够被XDoclet访问到。注释块一般都与Java源文件中的某个实体有关，并紧跟在这个实体的前面。没有紧跟实体的注释块将不会被处理。类（或者接口）可以有注释块，方法和域也可以有自己的注释块，比如：<br />/**<br />* 类注释块<br />*/<br />public class SomeClass {<br />　　/** 域注释块 */<br />　　private int id;<br />　　/**<br />* 构造函数注释块<br />*/<br />　　public SomeClass() {<br />　　　　// ...<br />　　}<br />　　/**<br />　　 * 方法注释块<br />　　 */<br />　　public int getId() {<br />　　　　return id;<br />　　}<br />}<br />注释块分成两部分：描述部分和标签部分。当遇到第一个javadoc标签时，标签部分开始。Javadoc标签也分成两部分：标签名和标签描述。标签描述是可选的，并且可以多行。例如：<br />/**<br />* 这是描述部分<br />* @tag1 标签部分从这里开始<br />* @tag2<br />* @tag3 前面一个标签没有标签描述。<br />* 这个标签有多行标签描述。<br />*/<br />XDoclet使用参数化标签扩展了javadoc标签。在XDoclet里，你可以在javadoc标签的标签描述部分加入name=”value”参数。这个微小的改动大大增强了javadoc标签的表达能力，使得javadoc标签可以用来描述复杂的元数据。下面的代码显示了使用XDoclet属性描述实体Bean方法：<br />/**<br />* @ejb.interface-method<br />* @ejb.relation<br />* name=”blog-entries”<br />* role-name=”blog-has-entries”<br />* @ejb.value-object<br />* compose=”com.xdocletbook.blog.value.EntryValue”<br />* compose-name=”Entry”<br />* members=”com.xdocletbook.blog.interfaces.EntryLocal”<br />* members-name=”Entries”<br />* relation=”external”<br />* type=”java.util.Set”<br />*/<br />public abstract Set getEntries();<br />参数化标签允许组合逻辑上相关联的属性。你可以加入描述这个类的元信息，使得这个类的信息足够生成代码。另外，程序员借由阅读这样的元信息，可以很快的理解这个类是如何使用的。（如果这个例子上的元信息你看不懂，不要担心，在第4章里，我们会学到EJB相关的标签以及它们的涵意。）<br />另外，请注意上面的例子中，所有的标签名都以ejb开头。XDoclet使用namespace.tagname的方式给标签提供了一个命名空间。这样做除了可以跟javadoc区别开来以外，还可以把任务相关的标签组织起来，以免任务之间的标签产生混淆。 <br /><br />2.5 代码生成模式<br />XDoclet是一种基于模板的代码生成引擎。从高层视图上来看，输出文件其实就是由解析执行各式各样的模板生成出来的。如果你理解了模板以及它所执行的上下文环境，就可以确切的认识到，XDoclet可以生成什么，不可以生成什么。如果你正在评估XDoclet平台，理解这些概念是非常重要的。要不然，你可能会错过XDoclet的许多强大的功能，也可能会被XDoclet的一些限制感到迷惑。<br />XDoclet运行在在Ant构建文件环境中，它提供了Ant自定义任务和子任务来与XDoclet引擎交互。任务是子任务的容器，子任务负责执行代码生成。子任务调用模板。模板提供了你将生成代码的饼干模子。XDoclet解析输入的源文件，提取出源文件中的XDoclet属性元数据，再把这些数据提供给模板，驱动模板执行。除此之外，模板还可以提供合并点(merge points)，允许用户插入一些模板片断(合并文件merge files)来根据需要定制代码生成。<br />2.5.1 模板基础<br />XDoclet使用代码模板来生成代码。模板(template)是你想生成文件的原型。模板里使用一些XML标签来指导模板引擎如何根据输入类以及它们的元数据来调整代码的生成。<br />[定义：模板(template)是生成代码或描述文件的抽象模视图。当模板被解析的时候，指定的细节信息会被填入。]<br />模板一般情况下会有一个执行环境。模板可能应用在一个类环境(转换生成transform generation)，也有可能应用在一个全局环境(聚集生成aggregate generation)。转换生成和聚集生成是XDoclet的两种类型的任务模式，理解它们之间的区别对于理解XDoclet是非常重要的。<br />当你使用XDoclet生成布置描述符文件时，你使用的是聚集生成。布置描述符文件并不仅仅只与一个类相关，相反，它需要从多个类里聚集信息到一个输入文件。在这种生成模式里，解析一次模板只会生成一个输出文件，不管有多少个输入文件。<br />在转换生成模式里，模板遇到每一个源文件就会解析一次，根据该文件类的上下文环境生成输出。这种生成模式会为每一个输入文件生成一个输出文件。<br />转换生成模式的一个很好的例子是生成EJB的local和remote接口。显然，接口是和Bean类一一相关的。从每一个类里提取信息(类以及它的方法、域、接口以及XDoclet属性等信息)转换出接口。除此以外，不需要其他的信息。<br />从实现里提取出接口似乎有点反向。如果你手写程序的话，一般来说会先定义一个接口，然后再写一个类来关现它。但XDoclet做不到，XDoclet不可能帮你实现一个已有接口，因为它不可能帮你生成你的业务逻辑。当然，如果业务逻辑可以从接口本身得到(比如JavaBean的get/set访问器)或者使用XDoclet属性声明好，那么生成业务逻辑代码来实现一个接口也不是不可能。但一般情况下，这样做不太现实。相比而言，提供一个实现，并描述接口与这个实现之间的关联就容易多了。<br />聚集生成和转换生成主要区别在它们的环境信息上。即使一个代码生成任务中生成一个Java文件，一般也不常用聚集生成，因为生成一个Java类还需要一些重要信息如类所处的包以及你想生成的类名，在这种环境下是无法提供的。如果一定要使用聚集生成的话，那就需要在另一个单独的地方提供好配置信息了。<br />2.5.2 模板标签<br />在还没见到模板长啥样子之前，我们已经比较深入的认识它了。那模板文件究竟长啥样子呢？它有点像JSP文件。它们都包含文件和XML标签，生成输出文件时XML标签会被解析，然后生成文本并显示在XML标签所处的位置上。除了以XDt为命名空间打头的XML标签会被XDoclet引擎解析以外，其余的XML标签XDoclet会忽略不管。下面的代码片断显示了XDoclet模板的“经典造型”：<br />　　public class<br />　　　　&lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　Extends Observabe {<br />　　　　static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　　　_instance = null;<br />　　　　public static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClassOf&gt;<br />　　　　　　getInstance() {<br />　　　　　　if (_instance == null) {<br />　　　　　　　　_instance =<br />new &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;<br />　　　　　　　　　　&lt;/XDtClass:classOf&gt;();<br />　　　　　　｝<br />　　　　　　return _instance;<br />}<br />}<br />研究一下这个模板，你会发现，它生成的是一个类定义。这个类里定义了一个静态变量instance，并且使用一个静态方法来控制这个静态文件的访问。借助Java语法，你可以很容易的推断出那些XDoclet模板标签的目录是生成类名，虽然对于这个标签如何工作你还并不是很了解。<br />即使你从没打算过要自己写模板，但理解模板是如何被解析运行的还是很有必要的。迟早你会调用到一个运行失败的XDoclet任务，没有产生你所期望的输出，那么最快捷的找出原因的方法就是直接检查模板文件，看看是哪里出了问题。<br />让我们看一下生成静态域定义的片断：<br />static &lt;XDtClass:classOf&gt;&lt;XDtEjbFacade:remoteFacadeClass/&gt;&lt;/XDtClass:classOf&gt;<br />　　　　_instance = null;<br />在XDoclet的眼里，这段模板代码很简单，那就是：<br />　　static &lt;tag/&gt; _instance = null;<br />XDoclet解析执行标签，如果有输出的话，把输入置回到文本里去。有些标签会执行一些运算，把输出放回到一个流里。这样的标签称之为内容标签(content tags)，因为它们产生内容。<br />另一种类型的标签称之为BODY标签。BODY标签在开始和结束标签之间存在文本。而BODY标签强大就强大在这些文本自己也可以是一断可以由外围标签解析的模板片断。比如在上面的例子里，XDtClass:classOf标签，它们的内容就是模板片断：<br />　　&lt;XDtEjbFacade:remoteFacadeClass/&gt;<br />classOf标签解析这段模板，提取出全限制的内容，然后剃除前面的包面，只输出类名。BODY标签并不总是会解析它的内容，在做这件事之前，它们会事先检查一些外部判断条件(比如检查检查你正在生成的是一个接口还是一个类)。这里标标签称之为条件标签(conditional tags)。还有一些BODY标签提供类似迭代的功能，它的内容会被解析多次。比如一个标签针对类里的每一个方法解析一次内容。<br />XDoclet标签提供了许多高层次的代码生成功能，但是有时候，它们可能显得不够灵活，或者表达能力满足不了你的需要。这时候，相对于另外开发一套通用功能的模板引擎相比，你可以选择扩展XDoclet模板引擎。你可以使用更具表述能力、功能更加强大的Java平台开发你自己的一套标签。 <br /><br />2.6 使用合并定制<br />代码生成系统之所以使用的不多，主要原因就在于它们往往只能生成一些死板的、不够灵活的代码。大多数代码生成系统不允许你改动它们生成的代码；如果，如果这个系统不够灵活，你所能做到的最好的扩展就是应用继承扩展生成的代码，或者使用一些共通的设计模式(比如Proxy和Adaptor)来满足你的需要。无论如此，这都不是产生你想生成的代码的好办法。代码生成器最好能做到所生成即所得WYGIWYG(what you generate is what you get)，来取代你需要花费大量的时间来粉饰生成出来的并不满足要求的代码。所以，对于代码生成器来说，支持灵活的定制，是生成能够完全满足要求的代码的前提条件。<br />XDoclet通过合并点(merge points)支持定制??合并点是在模板文件定义里允许运行时插入定制代码的地方。有时候，合并点甚至可以影响到全局代码的生成，不但允许你添加一些定制内容，还可以从根本上改变将要生成出来的东西。<br />[定义：合并点(Merge points)是模板预先定义的允许你在代码生成的运行时加入定制内容的扩展点]<br />让我们研究一段从XDoclet源代码里摘取出来的模板代码。在为实体Bean生成主键的模板末尾，定义了这样一个合并点：<br />　　&lt;XDtMerge:merge file=”entitypk-custom.xdt”&gt;&lt;/XDtMerge:merge&gt;<br />如果你在你的merge目录下创建了一个名为entitypk-custom.xdt文件，那么这个模板文件的内容将会在这个合并点被包含进来。你的定制可以执行高层模板可以执行的所有强大功能，可以进行所有模板可以进行的运算(包括定义自定义标签，定义它们自己的合并点)。<br />上面的这种合并点，为所有的类环境使用了同一个文件。当然，也可以为每一个类环境使用不同的合并文件。如果你不想定制全部的类文件，或者你不想为了某些改动而重写模板的时候，这会很有用。不管动机是什么，逐类的合并点很容易识别出来：他们会在名字里包含一个XDoclet的逐类标记{0}。这里有一个生成ejb-jar.xml文件里的安全角色引用的例子：<br />　　&lt;XDtMerge:merge file=”ejb-sec-rolerefs-{0}.xml”&gt;<br />　　　　&lt;XDtClass:forAllClassTags tagName=”ejb:security-role-ref”&gt;<br />　　　　　　&lt;security-role-ref&gt;<br />　　　　　　　　&lt;role-name&gt;<br />&lt;XDtClass:classTagValue<br />tagName=”ejb:security-roleref”<br />paramName=”role-name”/&gt;<br />　　　　　　　　&lt;/role-name&gt;<br />　　　　　　　　&lt;role-link&gt;<br />　　　　　　　　　　&lt;XDtClass:classTagValue<br />　　　　　　　　　　　　tagName=”ejb:security-roleref”<br />　　　　　　　　　　　　paramName=”role-link”/&gt;<br />　　　　　　　　&lt;/role-link&gt;<br />　　　　　　&lt;/security-role-ref&gt;<br />　　　　&lt;/XDtClass:forAllClassTags&gt;<br />　　&lt;/XDtMerge:merge&gt;<br />这段模板会遍历工程里的所有Bean。对于每一个Bean，XDoclet先从Bean的文件名里提取出Bean名，然后替换{0}，再根据替换后的文件名去寻找合并文件。例如，如果你有一个名为BlogFacadeBean的Bean，XDoclet会尝试寻找一个名为ejb-src-rolerefs-BlogFacade.xml的合并文件。<br />如果找不到这个合并文件，则这个&lt;merge&gt;标签的内容模板会被解析。这意味着合并点不仅可以提供定制内容，还可以在一个模板文件里定义一个替换点，当定制内容不存在的时候使用替换点里的内容。不是所有的XDoclet任务都提供了有替换内容的合并点，一般来说，它们更倾向于只提供一个简单的合并点，仅仅当合并文件存在的时候解析并导入合并文件的内容。这取决于任务的开发者觉得哪种合并点更符合他的要求。<br />还有一点没有介绍到的是XDoclet如何定位合并文件，每一个XDoclet任务或者子任务都会提供一个mergeDir属性，这个属性用于设置你存放合并文件的目录。 <br /><img src ="http://www.blogjava.net/xzclog/aggbug/79151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xzclog/" target="_blank">xzc</a> 2006-11-05 08:26 <a href="http://www.blogjava.net/xzclog/archive/2006/11/05/79151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>