首页 > 其他分享 >用 XDoclet 减少代码膨胀[摘]

用 XDoclet 减少代码膨胀[摘]

时间:2023-09-04 17:37:08浏览次数:72  
标签:XDoclet Java 代码 生成 Ant 膨胀 public 模板


文章来源: http://www-900.ibm.com/developerWorks/cn/java/j-xdoclet/index.shtml

发现多功能的模板驱动的代码生成器

Sing Li
作者, Wrox Press
2004 年 11 月

开放源代码的 XDoclet 代码生成引擎,是许多领先的 Java 框架不可缺少的组成部分,常常被用作面向属性的编程和持续集成的引擎。但是 XDoclet 还有一些不太惹人注目的地方:对初级开发人员来说,它太难掌握、太难精通。在这篇文章中,流行作者 Sing Li 以 XDoclet 为对象,揭示了其内部简单却优雅的设计,使您能够理解这项技术,并将它应用在实践当中。

XDoclet 能够很容易成为您的 Java 编程工具箱中的一个更加通用的跨技术代码生成工具。不幸的是,开发人员经常忽视 XDoclet 的一般用途,只有将它捆绑在大型开发框架或者 IDE 中,作为其中的一个隐藏元素时,才会用到它。人们常常认为很难将 XDoclet 应用在定制解决方案上。这篇文章的目的就是要消除这个迷惑,把 XDoclet 从常见的复杂陷阱中解脱出来,并向您展示了如何能够利用这个代码生成引擎。

我会用一个实际的例子演示 XDoclet 的用途,该例子将接收一个 POJO(plain old Java object),并用 XDoclet 生成完整 Web 应用程序的全部文件,这些文件是把数据输入关系数据库所必需的。该示例使用了 XDoclet 的 自定义模板代码生成功能,以及它对 Hibernate 对象关系映射工具、Struct Web 应用程序框架和应用程序服务器的内部支持。(请参阅参考资料)。

智能代码生成器
XDoclet 的核心功能是根据以下组合来生成代码的(或者生成其他配置/数据文件):

  • 进行特殊标记的 Java 源文件。
  • 预先定义的模板。

与其他基于模板的代码生成技术(例如 Velocity;请参阅参考资料)相比,XDoclet 具有以下独特优势:

  • XDoclet 与 Apache Ant(请参阅参考资料)紧密集成,从而提供了高度自动化的操作。
  • 把控制代码生成和模板处理的 XDoclet 标签作为内联注释嵌入到 Java 源代码文件中。这消除了同步多个相关文件和控制文件的需要。
  • XDoclet 的内置 Java 解析器使用它对 Java 代码结构的深入理解,为输入的 Java 代码建立内部结构模型 。该结构模型又经常被叫作 元数据(metadata),因为它包含与关联代码有关的数据。
  • XDoclet 的模板生成逻辑拥有对输入 Java 代码的内部结构模型的完全访问权。

接下来,我将进一步研究 XDoclet 是如何工作的,以帮助您理解这些特性。

XDoclet 操作
图 1 显示了 XDoclet 要求的输入和生成的输出。

图 1. XDoclet 黑盒子

您可以看到,包含嵌入式 XDoclet 标签的 Java 源代码是系统的输入。在 Apache Ant 的驱动下,XDoclet 处理输入的代码,生成的输出文本文件可以是 Java 源代码、HTML 页面、XML 文件等。为了处理输入,XDoclet 需要使用模板(保存在 .xdt 文件中)和标签处理器(用 Java 编码)。XDoclet 把模板和标签处理器打包成“模块”,不同的“模块”处理不同的问题域。

XDoclet 生成的结构模型
XDoclet 对包含嵌入式 XDoclet 标签的输入 Java 源代码进行解析,并为代码建立非常详细的结构模型。结构模型中的每个元素都代表源代码中的一个 Java 结构。图 2 显示的结构模型,揭示了 XDoclet 跟踪的代码构造和关系。

图 2. XDoclet 的解析的 Java 源代码的内部结构模型

图 2 中的结构模型跟踪类、接口、方法之类的代码构造(模型元素)。该模型还跟踪元素之间的关系,例如继承和接口实现。以内联注释的形式嵌入在源代码中的 XDoclet 标签被解析为模型元素的属性,并被跟踪。



深入 XDoclet
图 3 显示了 XDoclet 的内部结构,揭示了使其运行的功能块。

图 3. XDoclet 内部的功能块

如图 3 所示,Apache Ant 在运行的时候控制着 XDoclet 的配置和操作。XDoclet 解析输入的 Java 源代码,并在内存中生成结构模型。模板引擎通过处理一组模板和标签处理器,生成输出文件。模板和标签处理器可以是内置的,也可以是定制的。在代码生成期间,模板和标签处理器拥有对结构模型的完全访问。

XDoclet 虚假的复杂性
XDoclet 实质上就是一个通用的 Javadoc 引擎(请参阅侧栏,通用的 Javadoc 引擎)。那么,是什么让它看起来这么复杂呢?答案在于:XDoclet 几乎从未被单独讨论过,而总是藏在其他许多复杂的技术中。图 4 显示了了围绕在 XDoclet 周围的复杂性迷雾(请参阅侧栏为什么 XDoclet 看起来比实际的要复杂得多)。



图 4. XDoclet 的复杂耦合

在图 4 中,您可以看到 XDoclet 与以下内容是紧密相关的:

  • Apache Ant,它控制着 XDoclet 的操作。XDoclet 是作为一组 Ant 任务存在的,没有 Ant 则不能执行。
  • 与生成文件关联的具体问题领域的一些细节。

XDoclet 本身却是惊人地简单,正如下面示例中的工作代码所示的那样。

使用 XDoclet
现在,您可以通过研究我向您提供的数据入口应用程序示例,来观察 XDoclet 的实际工作。(要下载这个示例中使用的 Java 代码、XDoclet 模板和 Ant 脚本,请单击本文顶部或底部的 Code 图标,或者请参阅下载部分。)我们将从检查清单 1 所示的 Java 代码开始,这部分代码表示了一个客户的地址。该地址被编码成 JavaBean 组件,其中的 XDoclet 标签是以黑体字形式显示的:

清单 1. 用 XDoclet 标签标记的 AddressBean.java 源文件


package com.ibm.dw.beans;
import java.io.Serializable;
/**
* @dw.genStrutsAction action="/addAddress.do"
* @hibernate.class table="ADDRESS"
*/
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() {
}
/**
* @dw.genStruts formlabel="Street Number"
* @hibernate.property length="10"
*/
public String getStreetNumber() {
return streetNumber;
}
public void setStreetNumber(String inpStreetNumber) {
streetNumber = inpStreetNumber;
}
/**
* @dw.genStruts formlabel="Street"
* @hibernate.property length="40"
*/
public String getStreet() {
return street;
}
public void setStreet(String inpStreet) {
street = inpStreet;
}
...... more Address bean properties ......
/**
* @hibernate.id generator-class="native"
*/
public long getId( )
{
return id;
}
public void setId(long inId) {
id = inId;
}
}

在清单 1 中,需要注意的是,要把 XDoclet 标签嵌入到注释中,紧放在相关代码元素(例如字段、方法、接口或类)的前面。在解析源代码时,XDoclet 会为每个标签建立一个属性,并将该属性附加到结构模型的代码元素上。现在,请注意 @dw.genStruts 标签,因为这是在本例中将用到的第一个模板。

生成另外一个 Java 类
对于本例,您需要生成新的 Java 类的代码 —— 一个 Struts 表单 bean。Struts 会用这个 bean 保存并传输用户输入。bean 必须以 bean 属性的形式包含所有数据字段,而且它必须是 org.apache.struts.action.ActionForm 的子类。

为了生成表单 bean 的代码,您要根据清单 2 所示的伪代码生成 XDoclet 模板。括号中的黑体字代表控制流逻辑和您要进行替换的文本。请注意模板是如何从已解析的 Java 源代码文件的结构模型中提取信息的:

清单 2. 建立 AddressBeanForm.java Struts 表单 bean 代码的伪代码模板



package {package name of source class};
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 {name of source class};.
*
* @struts.form name="{name of source class}Form"
*/
public class {name of source class}Form extends ActionForm {
{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 }
private {return type of method}{name of the JavaBean property};
public {return type of method}{name of the getter method for this property}(){
return {name of JavaBean property};
}
public void {name of the setter method for this property}(
{return type of method} value) {
{name of the JavaBean property} = value;
}
{end of if @dw.genStruts}
{end of if JavaBean getter}
{end of loop}



在清单 2 的循环中的代码生成了一个字段声明和一个访问器方法,还为输入源代码中每个用 @dw.genStruts 标记的访问器方法生成了一个设置器方法。

清单 2 使用了易于理解的伪代码来表示模板替换标签。实际的 XDoclet 模板标签则相当繁琐。清单 3 显示了 genformbean.xdt 模板(所有的 XDoclet 模板都保存在 .xdt 文件中)。我已经用黑体字强调了 XDoclet 模板标签,以方便在伪代码中对其进行引用。

清单 3. 建立 Structs 表单 bean Java 代码的实际 XDoclet 模板代码


package <XDtPackage:packageName/>;
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 <XDtClass:className/>.
*
* @struts.form name="<XDtClass:className/>Form"
*/
public class <XDtClass:className/>Form extends ActionForm {
<XDtMethod:forAllMethods>
<XDtMethod:ifIsGetter>
<XDtMethod:ifHasMethodTag tagName="dw.genStruts">
private <XDtMethod:methodType/> <XDtMethod:propertyName/>;
public <XDtMethod:methodType/> <XDtMethod:getterMethod/>(){
return <XDtMethod:propertyName/>;
}
public void <XDtMethod:setterMethod/>(<XDtMethod:methodType/> value) {
<XDtMethod:propertyName/> = value;
}
</XDtMethod:ifHasMethodTag>
</XDtMethod:ifIsGetter>
</XDtMethod:forAllMethods>


您可以参考 XDoclet 的“模板语言”文档,查找 XDoclet 所有可用标签的列表(请参阅参考资料)。

要运行用于 AddressBean.java 源文件的模板,请使用以下 Ant 命令行:

这个命令可以执行定制 Ant 目标(请参阅侧栏熟悉 Ant 脚本编写)来处理 genbeanform.xdt 模板。XDoclet 提供的 Ant 任务叫作 xdoclet.DocletTask,它被用来运行模板文件。如果您对 Ant 的细节感兴趣,请参阅示例代码中的 build.xml 文件,以了解更多信息。

在 XDoclet 处理模板的时候,它在名为 generated

清单 4. XDoclet 生成的包含 Struts 表单 bean 的 Java 源代码

package com.ibm.dw.beans;
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 AddressBean.
*
* @struts.form name="AddressBeanForm"
*/
public class AddressBeanForm extends ActionForm {
private java.lang.String streetNumber;
public java.lang.String getStreetNumber(){
return streetNumber;
}
public void setStreetNumber(java.lang.String value) {
streetNumber = value;
}
private java.lang.Stringstreet;
public java.lang.String getStreet(){
return street;
}
public void setStreet(java.lang.String value) {
street = value;
}
...... more bean properties .....
}

为数据表单输入生成 JSP 页面
您可以用相同的 AddressBean.java 源文件,但是用 genformjsp.xdt 模板生成数据入口表单 JSP 页面。清单 5 显示了 genformjsp.xdt:

清单 5. 使用 Struts 标签库生成 JSP 页面来显示 HTML 表单的 XDoclet 模板

请注意,代码中用 <XDt:methodTagValue> 取得原始 AddressBean.java 代码中在 XDoclet 标签中指定的属性值。

当您执行 genstruts Ant 目标的时候,也会处理清单 5 显示的 genformjsp.xdt 模板。您可以在 generated

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head>
</head>
<body bgcolor="white">
<html:errors/>
<html:form action="<XDtClass:classTagValue tagName='dw.genStrutsAction' paramName='action' /> >"
<table border="0" width="100%">
<XDtMethod:forAllMethods>
<XDtMethod:ifIsGetter>
<XDtMethod:ifHasMethodTag tagName="dw.genStruts" >
<tr>
<th align="right">
<XDtMethod:methodTagValue
tagName="dw.genStruts" paramName="formlabel"/>
</th>
<td align="left">
<html:text property="<XDtMethod:propertyName/>"
size="<XDtMethod:ifHasMethodTag tagName="hibernate.property" >
<XDtMethod:methodTagValue tagName="hibernate.property" paramName="length"/>
</XDtMethod:ifHasMethodTag>"/>
</td>
</tr>
</XDtMethod:ifHasMethodTag>
</XDtMethod:ifIsGetter>
</XDtMethod:forAllMethods>
<tr>
<td align="right">
<html:submit>
Submit
</html:submit>
</td>
<td align="left">
<html:reset>
Reset
</html:reset>
</td>
</tr>
</table>
</html:form>
</body>
</html:html>


生成其他工件
您可以用 XDoclet 生成任意基于文本的输出。我向您展示的例子使用 XDoclet 生成了 Java 代码、JSP 页面、XML 文件、配置文件以及其他更多输出。它从一个简单的用 XDoclet 进行标记的 Java 源文件 AddressBean.java,建立了一个完整的数据入口 Web 应用程序。为了做到这一点,它执行了 XDoclet 的内置模板(位于 JAR 文件中,称为模块),从而生成:

  • Struts 配置和支持文件。
  • Hibernate 配置和支持文件。
  • Web 应用程序的部署描述符(web.xml)。

表 1 显示了为示例应用程序生成的所有文件(通常称为工件(artifact)):

表 1. XDoclet 为 AddressBean.java 生成的工件

用 XDoclet 减少代码膨胀[摘]_struts

在这篇文章中,您详细了解了表 1 中所列的两个工件中的第一个工件的生成,深入了解了生成它们的模板。工件 AdddressBeanAction.java 则用类似的方法,利用叫作 genaction.xdt 的模板生成。XDoclet 具有内置模板和标签处理器,可以生成表 1 中的其他工件。

表 2 列出了每个生成的工件对应的 Ant 目标和 Ant 任务。您可以执行表格中的每个 Ant 目标,生成对应的工件。所有这些生成的工件,再加上原始和 AddressBean.java,共同构成了示例 Web 应用程序。您还会发现叫作 all 的默认 Ant 目标,它会为您做任何事,包括为应用程序建立 WAR(可以部署的 Web 归档)。在进行处理之前,一定要阅读代码发布包中的 README.txt 文件。



表 2. 对应于生成工件的 Ant 目录和 Ant 任务

用 XDoclet 减少代码膨胀[摘]_ant_02

结束语
XDoclet 是一个有用的、智能的代码生成器,您可以用它自动进行许多日常的 Java 开发任务。不要被它表面的复杂所吓退。随着逐渐精通 XDoclet(以及与之相关的 Apache Ant),您会节约您宝贵的时间,并在未来的开发工作中,得到数倍的回报。

参考资料


下载

内容:智能代码生成器深入 XDoclet 使用 XDoclet 结束语参考资料 下载关于作者对本文的评价

标签:XDoclet,Java,代码,生成,Ant,膨胀,public,模板
From: https://blog.51cto.com/u_16245757/7353213

相关文章

  • iOS代码加固与保护方法详解 - 提升iOS应用安全性的关键步骤
    摘要:作为一名从事iOS开发多年的技术博主,长期以来我都没有重视代码加密和加固。然而,最近了解到使用IPAGuard工具可以对iOS应用进行混淆保护,我开始重新审视iOS应用的安全性问题。本文将详细介绍如何使用IPAGuard工具进行代码加固和保护,以提高iOS应用的安全性和抵御逆向分析的风险。......
  • 已知16进制和透明度,使用JS语法求他们在一起的rgba。可以参考下面代码:
    事件起因:最近做的一个大转盘游戏页面样式编辑,背景透明度调整的时候,会导致字体一起变动,于是需要将背景演示的16进制和透明度一起转换成rgba。 functionhexToRgba(hex,alpha){//去掉可能包含的"#"符号if(hex.startsWith("#")){hex=hex.slice(1);}//解析1......
  • iOS代码加固与保护方法详解 - 提升iOS应用安全性的关键步骤
    摘要:作为一名从事iOS开发多年的技术博主,长期以来我都没有重视代码加密和加固。然而,最近了解到使用IPAGuard工具可以对iOS应用进行混淆保护,我开始重新审视iOS应用的安全性问题。本文将详细介绍如何使用IPAGuard工具进行代码加固和保护,以提高iOS应用的安全性和抵御逆向分析的风险......
  • 起盟生活APP系统开发设计和部分远源代码分享
    起盟生活也是一种卷轴模式,卷轴模式从趣步模式开始到现在,不断有新的项目出来,如果说2023年商业模式项目做个排行,我想有一半的项目是卷轴模式的项目,它的特点也很明显,互联网生意讲究免费,羊毛出在猪身上狗来买单的逻辑.免费,让所有人都能参与进来玩,免费,让系统本身具备分销裂变的属性,可以......
  • 百度上传下载控件代码
    ​ 需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。 第一步:前端修改由于项目使用的是BJUI前端框架,并没有使用框架本身的文件上传控件,而使用的基于jQuery的Uploadify......
  • 使用百度文心一言生成bat代码(查找当前目录所有文件名带11的txt文件并修改为22)
    百度文心一言开放给普通用户了,网址:文心一言请用[bat]编程:查找当前目录所有文件名带11的txt文件并修改为22生成的代码需要简单修改下,主要问题在->位置没有使用转义符会导致echo后面的字符到txt中,思路还是可以的,不错点击查看代码@echooffsetlocalenabledelayedexpansion......
  • 【ECAPA_TDNN 下 】代码和论文细节分析
    【ECAPA-TDNN上】论文阅读https://blog.csdn.net/qq_32766309/article/details/121359110?spm=1001.2014.3001.5502【ECAPA_TDNN下】代码和论文细节分析https://blog.csdn.net/qq_32766309/article/details/124243147?ops_request_misc=%257B%2522request%255Fid%2522%253A%......
  • ECAPA-TDNN代码阅读
    https://blog.csdn.net/JYT666666/article/details/130209208?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169355260816800225596318%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169355260816800225596318&......
  • 代码随想录算法训练营第二十九天| 491.递增子序列 46.全排列 47.全排列 II
     491.递增子序列   卡哥建议:本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。 https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html  视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v  做题思路......
  • 代码随想录算法训练营第三十天| 51. N皇后 37. 解数独 总结
        卡哥建议:今天这三道题都非常难,那么这么难的题,为啥一天做三道? 因为 一刷 也不求大家能把这么难的问题解决,所以 大家一刷的时候,就了解一下题目的要求,了解一下解题思路,不求能直接写出代码,先大概熟悉一下这些题,二刷的时候,随着对回溯算法的深入理解,再去解决如下三题。 ......