XDoclet: "懒惰者"的掌中利器

Perl 语言的发明人Larry Wall曾经把懒惰称为是程序员的一种“美德”,我想如果你是具备这样一种“美德的程序员,一定不会对“代码自动生成”这一概念等闲视之,看看 Eclipse上著名的Lomboz插件以及开源社区广为流行的AndroMDA吧,它们就是基于这种“代码自动生成”的产物。如果你恰巧是具备了这种 “美德”的Java程序员,那么XDoclet将是你所梦寐以求的工具。

 

代码自动生成和XDoclet 的由来

在软件开发的历史中,代码自动生成的思想并不是一个很时髦的概念了,XDoclet同样也不是唯一的代码自动生成工具,我们所熟悉的IDE开发环境中的代码向导,甚至流行的JSP技术(也不过就是从JSP自动生成servlet)等等,这种让程序来写代码的思想比比皆是。定义一个代码生成要求规范作为代码自动生成的输入——代码生成器读入这个抽象的要求规范,然后借助于模板,输出一个或多个符合那个抽象要求规范的输出文件,这就是代码生成的大体流程。主要有主动式和被动式两种类型的码生成方式,两者的区别在于代码生成在开发过程中所扮演的角色。在被动式的代码生成方式中,代码被一次性生成并由开发者来编辑修改生成的结果输出文件(例如IDE中的代码向导);与此相反,在主动式的代码生成方式中,开发者需要编辑并修改的是代码生成器的输入文件而不是生成的输出文件,两者的区别是显而易见的。本文介绍的XDoclet工具属于主动式的代码生成方式。

XDoclet 最初源于数年前Rickard Oberg在为JBoss应用服务器开发EJB容器的时侯,自称具备懒惰“美德”的Oberg发现为每个EJB组件编写大量的接口和部署描述符实在是一个巨大的负担,并由此开了一个称为EJBDoclet的工具,这就是XDoclet的前身。

 

什么是XDoclet?

XDoclet是一个开放源码的、可扩展的、元数据驱动的、面向属性(Attribute Oriented Programming)的Java代码生成引擎,它使Java具备了面向属性编程的能(Java通过XDoclet具备了.NET吹嘘的“属性”功能)。这意味着你可以凭借在Java源代码中附加元数据这种方式来为你的代码添加更多的重要特性,这里所说的元数据其实就是属性,通过特定的 JavaDoc 标签把属性添加到代码中,XDoclet将对你的源代码进行解析,并依据那些元数据生成诸如XML格式的部署描述符、接口一些文件或其他的源代码。当然,在生成过程中还需要借助于一些模板,模板利用提供在源代码中以及JavaDoc 标签中的信息来具体生成输出文件。XDoclet虽然建立在EJBDoclet思想的基础上,但适用范围不再局限于EJB,现在我们已经可以用 XDoclet生成Web Service、部署描述符,甚至还可以对它进行扩展,满足自己的特殊需要。

一个XDoclet标签通常由如下几部分组成:

@namespace.tag-name attribute-name="attribute value"

从概念上看与一个XML元素非常相似,都具有标签名和可选的一系列属性,不同之处是语法上的差异。标签依据名称空间(namespace)分组,并且在那个名称空间中有一个唯一的名字。标签可以有零个或多个属性,并且按照名字=“值”对这种方式分割。这里简单解释一下名称空间的作用,名称空间是用来确保名字不发生冲突的一种机制,常用的名称空间包括:ejb、web、jboss、weblogic、struts等等,它把相关的标签进行了分组。此外,标签的值可以被指定为Ant属性,如下代码所示:

@jboss.create-table create="${jboss.create.table}"

其中jboss.create.table就是一个在Ant项目中定义的属性。标签一般存在于类和方法这一层次(在极少数情况下也可以存在于类的数据属性字段和构造方法这一层次)。一个一般化的原则是:如果从类的名字或类型可以确定信息,就没有必要用标签来专门指定那个信息了。

典型的XDoclet标签实例如下所示:

/*This is the Account entity bean. It is an example of how to use the * EJBDoclet tags. * @see Customer * @ejb.bean * name="bank/Account" * type="CMP" * jndi-name="ejb/bank/Account" * local-jndi-name="ejb/bank/LocalAccount" * primkey-field="id" * @ejb.finder * signature="java.util.Collection findAll()" * unchecked="true" * @ejb.transaction * type="Required" * @ejb.interface * remote-class="test.interfaces.Account" * @ejb.value-object * match="*" * @version 1.5*/

注意:上述例子中包含了3个部分:注释、javadoc标签和XDoclet标签。其中头两个部分是标准的注释文档,并没有因为使用了XDoclet而影响了它们本身正常功能的使用,第三个部分才是我们真正感兴趣的部分。

 

XDoclet 的任务、子任务和模板

虽然XDoclet起源于一个创建EJB的工具,但是目前已经逐渐发展为一个通用的代码生成引擎,XDoclet由一个内核和数量不断增长的模块(也就是 XDoclet模板)组成,如果有针对某种新组件的需求,开发一个新模块是相当简单的工作。下面我们就来分别看看XDoclet的几个核心概念:任务、子任务和模板。

 

XDoclet 任务

这里所谓的任务指的是在XDoclet中可用的高层次的代码生成功能,或者也可以说是核心的功能化模块。每个这样的任务关注于某一个特定的技术领域,下面列出主要的XDoclet 任务:

<ejbdoclet>

生成EJB - enterprise bean、工具类和部署描述符。

<webdoclet>

有关Web 开发 - servlet、filter(过滤器)、taglib(标签库)和Web框架。

<hibernatedoclet>

hibernate 持久化 - 配置、Mbean等。

<jdodoclet>

JDO - 元数据、提供商配置等。

<jmxdoclet>
JMX  -  MBean 接口、mlets和配置文件。
<doclet>
用于特殊代码生成的客户模板。
<documentdoclet>
项目文档。
其中<ejbdoclet>是到目前为止应用最为广泛的XDoclet任务,其次用得最多的就是<webdoclet>任务。

 

子任务

这里所谓的子任务就是由一个特定任务所提供的单一目的的代码生成过程,一个XDoclet任务就是这些关注于某一个领域的、更为细化的一系列子任务的集合。任务对相关的子任务进行管理和分组,并由子任务执行具体的代码生成。举例来说,当你要生成EJB组件时,你需要为每个bean生成一个home接口、一个remote接口以及一个e j b - j a r . x m l 部属描述符,这些就是<ejbdoclet>任务中的三个独立的代码生成子任务。

 

模板(Template)

模板就是包含一些代码以及用于生成最终源代码的、类似XML形式的语法文件,模板文件中包含了通用的Java关键字以及由类似XML标签组成的一些结构,这些标签结构便于XDoclet从输入的源文件中获取相关的信息。XDoclet利用模板这样一种设计使得你可以非常容易的编写自己的特定模板,在你的代码中找到重复的部分,然后编写特定的XDoclet模板来自动生成它们,从而使XDoclet具有很强的可扩展性。

 

与Ant的集成

XDoclet 是借助于Ant 之类的build 工具并作为build过程的一个部分来使用的,XDoclet的任务也是作为Ant build的任务来执行的(如左图所示),目前Ant已成为事实上的Java标准构建工具。在使用XDoclet任务之前,首先需要用A n t 的<taskdef>来声明一下,下述代码在Ant中声明了一个<ejbdoclet>任务:

<taskedf name= “ejbdoclet”  classname= “xdoclet.modules.ejb.EjbDocletTask” classpathref= “xdoclet.lib.path”/>

其中classname和classpathref属性告知Ant工具何处来定位实现这个任务的XDoclet类,详细内容在下面使用XDoclet”一节具体介绍。

 

安装XDoclet

XDoclet可以运行在装有Java 2 运行环境的任何平台上,到目前为止XDoclet 已经被成功的用于包括Linux、UNIX、Windows 9x、NT、2000 、XP和MacOSX等许多平台。首先你必须确认JDK 的lib目录下tools.jar 文件已经正确的设置到classpath中,并且使用的是Jakarta Ant 1.5 以上版本(XDoclet不支持以前的版本)。安装过程非常简单,只需从SourceForge 下载最新的XDoclet版本(xdoclet-bin-1.2.1版),解压到你指定的目录下即可,解压后会看到在XDoclet目录下有docs、 lib 和samples 三个子目录。

 

使用XDoclet

这里我们通过一个具体的实例来详细介绍XDoclet的使用方法,XDoclet的使用其实是非常简的,就像给你的代码添加JavaDoc 注释一样,只不过这里添加的是XDoclet标签。XDoclet标签是作为元数据提供者来使用的,元数据被用来生成所要求的输出文件。

在开始使用XDoclet之前,首先必须确定你希望用XDoclet来生成什么?最常用的两个任务是ejbdoclet和webdoclet。通常情况下你需要为Ant定义XDoclet 任务、设置配置参数(如下例所示):

<path id="project.class.path"> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> </path> <target name="ejbdoclet" depends="prepare"> <taskdef name="ejbdoclet" classname="xdoclet.modules.ejb.EjbDocletTask" classpathref="project.class.path"/> <tstamp> <format property="TODAY" pattern="d-MM-yy"/> </tstamp> <ejbdoclet destdir="${generated.java.dir}" excludedtags="@version,@author" addedtags="@xdoclet-generated at ${TODAY}" ejbspec="2.0"> <fileset dir="${java.dir}"> <include name="**/*Bean.java"/> </fileset> <dataobject/> <packageSubstitution packages="persistence" substituteWith="interfaces"/> <remoteinterface pattern="{0}Remote"/> <localinterface pattern="{0}"/> <homeinterface /> <localhomeinterface/> <entitypk/> <entitycmp/> <deploymentdescriptor destdir="${build.dir}/ejb/META-INF"/> <jboss version="3.0" securityDomain="java:/jaas/samples" preferredRelationMapping="relation-table" datasource="java:/DefaultDS" datasourcemapping="Hypersonic SQL" destdir="${build.dir}/ejb/META-INF"/> </ejbdoclet> </target> <target name="compile" depends="ejbdoclet"> <!-- Compile EJBs --> <javac srcdir="${java.dir}:${generated.java.dir}" destdir="${build.dir}/ejb" includes="test/ejb/*.java, test/interfaces/*.java"> </target>

在这个例子中compile target(编译目标)依赖于ejbdoclet target,这里所说的依赖的意思是:在编译任何东西以前,所有的home、local、remote 接口, 主键, 数据对象和部署描述符统统已被生成。当然,你首先要做的就是为Ant定义这个ejbdoclet任务。为此需要用到taskdef标签,在这个标签里指定了xdoclet.modules.ejb.EjbDocletTask作为实现ejbdoclet 任务的类。注意:标签里的属性classpathref指向标识为“project.class.path”的路径,这个路径包含所有的XDoclet jar和commons-logging.jar文件。下一步需要用一系列配置参数和嵌套的元素来声明ejbdoclet 任务,正如你所见,这里也可以使用继承机制,可以为每一个嵌套元素(或者也可以称为子任务)重载destdir属性参数。元素<deploymentdescriptor/>就重载了destdir属性,重新定义了生成的ejb-jar.xml文件的存放位置。缺省情况下,每一个任务都有自己的内置的子任务,其中有些是强制性的,例如<remoteinterface/> 和<localinterface/>,你能想象出一个没有remote 或localEJB 2.0 ) 接口的EJB吗?其它的一些则是可选的,例如<jboss/>,你当然可以有其它的应用服务器选择。还有第三种形式的子任务:<template/>。这在你要设计自己的模板来生成定制的文件时是非常有用的,因此,你需要一种简单的方式以使XDoclet来使用你的模板。如下例所示:

<taskdef name="templatedoclet" classname="xdoclet.DocletTask" classpathref="project.class.path"/> <templatedoclet destdir="${generated.java.dir}" excludedtags="@version,@author"/> <fileset dir="${java.dir}"> <include name="**/*Bean.java"/> </fileset> <template templateFile="/mytemplate.xdt" destinationfile="mygeneratedfile.txt"/> </templatedoclet>

这样你就可以在任务中放置< template />元素标签,并指定你自己的模板文件路径和输出文件名(存储在destdir属性指定的目录中)。这一特性对于那些想要充分发挥XDoclet的性能定义自己的@tag(元素标签)和模板的具有创造性的开发者来说是非常有用的。

 

XDoclet 带给我们的益处

目前XDoclet 的发行包中绑定的模块支持几乎所有的主流应用服务器,包括:JBoss、 BEA WebLogic、IBM WebSphere、Oracle IAS、 Orion、Borland、MacroMedia JRun、Jonas、Pramati和Sybase EAServer等等;支持的工具和框架包括:Castor、Hibernate、JDO、Struts、WebWork和MockObjects等等流行的工具和框架。这为我们项目的开发提供了范围广大的选择余地。XDoclet可以使你在面向组件的开发过程中运用XP所积极倡导的持续集成(Continuous Integration)开发方式,并且在EJB组件的开发中开发者只需集中编辑唯一一个Java源代码文件即可。这带来的好处是不言而喻的:首先,每个组件只与一个文件打交道会使你比较清晰地了解组件的整个概貌,这在当组件包含多个文件的情况下好处是非常明显的。如果你曾经开发过EJB组件你就会很容易理解了,通常单个EJB组件会包含7个以上的文件,这时借助XDoclet你仅仅需要维护一个文件,其余的文件让代码自动生成。其次,使用XDoclet 可以大幅简化J2EE应用的开发工作,你可以编写enterprisebean的具体实现,让XDoclet去生成诸如Interface,value objects(值对象),struts forms等等其它的代码,而且XDoclet还遵循许多业界公认的J2EE模式。

 

结束语

得益于天才的懒惰“ 美德”,我们有幸拥有了XDoclet,凭借XDoclet我们可以显著缩减开发时间,并集中精力于我们的业务逻辑,经验表明:XDoclet可以生成大约85%的代码量。当我们坐享这丰盛的免费午餐时,你是否已从这种天才的懒惰“美德”中品味出了创造或者是创新的勤奋呢?

你可能感兴趣的:(java,应用服务器,ant,ejb,javadoc,任务)