Fenriswolf 程式筆記

奮利斯狼的地盤,小綿羊勿入

XDoclet 程式產生器 – 自訂 xdt template

有些程式不管命名或是程式架構都有一定的規則,如果都用手動的方式 copy、paste 蠻煩人的也容易出錯
一般 IDE 所提供的功能都不見得可以完全符合專案的需要,因此有了自己寫產生器的想法
不過找了一些如 Velocity 的工具發現並不好用,大部分的資訊都要自己寫 reflection 的程式碼
XDoclet 則有各種好用的 tags,還有提供接口可跟 ant 做很好的整合

假設有以下4個 classes
DaoAImpl.java

public class DaoAImpl extends HibernateDaoSupport implements DaoA {
    public void insert() {
        // dosomething
    }
}

DaoBImpl.java

public class DaoBImpl extends HibernateDaoSupport implements DaoB {
    public void insert() {
        // dosomething
    }
}

ServiceAImpl.java

public class ServiceAImpl implements ServiceA {
    private DaoA daoA;
    private ServiceB serviceB;

    public void run() {
        // dosomething
    }

    public void setDaoA(DaoA daoA) {
        this.daoA = daoA;
    }

    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

ServiceBImpl.java

public class ServiceBImpl implements ServiceB {
    private DaoB daoB;

    public void run() {
        // dosomething
    }

    public void setDaoB(DaoB daoB) {
        this.daoB = daoB;
    }
}

我希望可由 xdoclet 建立 spring mapping xml
撰寫自定的 xdoclet 有以下三個步驟
1. 定義 xdoclet template
命名為 spring_xml.xdt 並放到 com/fw/xdoclet/resources 下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
    default-lazy-init="true">

<XDtClass:forAllClasses>
    <bean id="<XDtSpringClass:springBeanName/>" class="<XDtClass:fullClassName/>">
        <XDtSpringClass:ifIsDao>    
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
        </XDtSpringClass:ifIsDao>
        <XDtMethod:forAllMethods>
        <XDtMethod:ifIsSetter>
        <property name="<XDtMethod:propertyName/>">
            <ref local="<XDtMethod:propertyName/>"/>
        </property>
        </XDtMethod:ifIsSetter>
        </XDtMethod:forAllMethods>
    </bean>
</XDtClass:forAllClasses>
</beans>

透過 xdt開頭的 tags 讀取相對應的訊息來產生我要的 xml
XDtClass:forAllClasses : 找出所有 classes,classes 的路徑會在 build.xml 內設定
XDtSpringClass:springBeanName : 自定的 xdt tag,在第二篇文章會有詳細說明
XDtSpringClass:ifIsDao : 也是自定的 xdt tag
XDtClass:fullClassName : 印出 class 的全名,包括 package name
XDtMethod:forAllMethods : 找出 class 內所有的 methods
XDtMethod:ifIsSetter : 判斷此 method 是否為 setter method
XDtMethod:propertyName : 列出 method name 但是去掉 set 前置字元
其他 xdoclet 預設的 tags 請看參考資料

2. 寫 ant task
SpringXmlSubTask.java,指定所要讀取的 xdt template 及預設 xml 的檔名(可在 build.xml 裡更改)

package com.fw.xdoclet;

import xdoclet.XmlSubTask;

public class SpringXmlSubTask extends XmlSubTask {
    private final static String DEFAULT_TEMPLATE_FILE = "resources/spring_xml.xdt";

    private final static String GENERATED_FILE_NAME = "spring.xml";
    
    public SpringXmlSubTask()
    {
        setTemplateURL(getClass().getResource(DEFAULT_TEMPLATE_FILE));
        setDestinationFile(GENERATED_FILE_NAME);
    }
}

3. 建立 xdoclet 的 mapping 檔
命名為 xdoclet.xml 並放到 META-INF 下

<xdoclet-module>
     <subtask
        name="springxml"
        implementation-class="com.fw.xdoclet.SpringXmlSubTask"
        parent-task-class="xdoclet.DocletTask" />
</xdoclet-module>

name : 在 build.xml 裡的 tag name
implementation-class : 上面寫的 SpringXmlSubTask
parent-task-class : base 的 ant task,在 build.xml 內用到

把以上幾個檔案包成 fwdoclet.jar 檔放到 ant build path,目錄結構如下
com/fw/xdoclet/SpringXmlSubTask.class
com/fw/xdoclet/resources/spring_xml.xdt
META-INF/xdoclet.xml

4. 寫 build.xml

<project name="xdoclet" default="springdoclet" basedir=".">
    <target name="init">
        <property file="build.properties"/>

        <path id="xdoclet.lib">
            <fileset dir="${lib.dir}">
                <include name="**/*.jar" />
            </fileset>
        </path>
    </target>

    <target name="springdoclet" depends="init">
        <taskdef name="springdoclet" classname="xdoclet.DocletTask">
            <classpath refid="xdoclet.lib" />
        </taskdef>

        <springdoclet destdir="${build.dir}">
            <fileset dir="${src.dir}">
                <include name="**/*Impl.java" />
            </fileset>

            <springxml destinationFile="appContext.xml" />
        </springdoclet>
    </target>
</project>

指定 xdoclet.DocletTask 為 base ant task
指定的 classes 會傳到 xdt template 內的
則是在 xdoclet.xml 內定義的 subtask name,並用 destinationFile 屬性更改預設的檔名(不設則產生 spring.xml)

最後是執行上面的 build.xml 產生的 appContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
    default-lazy-init="true">

    <bean id="daoB" class="com.fw.xdoclet.DaoBImpl">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

    <bean id="daoA" class="com.fw.xdoclet.DaoAImpl">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

    <bean id="serviceB" class="com.fw.xdoclet.ServiceBImpl">
        <property name="daoB">
            <ref local="daoB"/>
        </property>
    </bean>

    <bean id="serviceA" class="com.fw.xdoclet.ServiceAImpl">
        <property name="daoA">
            <ref local="daoA"/>
        </property>
        <property name="serviceB">
            <ref local="serviceB"/>
        </property>
    </bean>
</beans>

 
 
執行環境
JDK 1.6.0_03
XDoclet 1.2.3

參考資料
XDoclet
Template Language(xdt)

程式下載
spring_xml.xdt
SpringXmlSubTask.java
xdoclet.xml
build.xml

廣告

2012/03/19 - Posted by | Java Tool |

仍無迴響。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

%d 位部落客按了讚: