【第169期 October 5, 2011】
 

研發新視界

簡介Javadoc的doclet和taglet

作者/宋定遠

[發表日期:2011/10/3]


前言

Javadoc是JDK內附的一個工具程式,它所產出的文件是Java程式設計師的好朋友,尤其在使用一個自己不熟悉的Library時多多少少總是要翻一下它的文件。因此在絕大多數的情況下,我們是因為Library的作者妥善地使用了Javadoc而受惠,真的要謝謝他們,在程式寫完後還有心情把文件補得這麼齊全,雖然只是在註解中多寫一些字、再透過Javadoc自動產出文件而已,但卻大大降低了使用者在理解上的困難。

身為一個程式設計師應學習並培養使用Javadoc的習慣,不只是用來簡單介紹各個Method的用法或是類別的繼承關係,而是更進一步地讓Javadoc參與系統完整的開發流程,它的各個階段性任務如下:

一、開發初期,各個類別的劃分可能還只是想法沒有實作,我們除了將這個想法寫在紙上之外,還能寫在一個HTML檔案中作為整個系統Package的Overview;並且Javadoc在產出文件時並沒有要求所有類別都必需要編譯成功,因此在開始實作前,各個java檔案已經能在建構子或方法的註解內做初步的設計。

二、開發中期,總是會遇到一些因素讓我們不得不修改本來的設計,使用Javadoc能在最靠近修改之處寫下註釋,這個動作能幫助程式設計師在系統完成之後回想當初修改的理由(因為很難保證之後不會改回來)。

三、開發後期,程式設計師總免不了要做一個文件來說明系統的運作流程,如果全程都使用Javadoc來紀錄設計概念的演變,那麼所有撰寫文件需要的細節都會在source code中找到,降低系統完成後還要寫文件的煩燥感。

更重要的是,在每一次寫下修改紀錄時我們都有機會重新審視目前的設計,看處理的流程是否合理、或是否有更好的改法,有彈性的系統骨架能避免很多未來可能要大幅改動的可能性,這對於我們程式設計師來說是很重要的。

然而,當我們想使用Javadoc來紀錄各式各樣的資訊時,很有可能遇到"預設的標籤不敷使用"的情況,可能資訊出現的位置不夠理想、也可能某類資訊需要固定的處理而不想每次都手動修改,因此我們就會想要客製化的標籤和訊息格式,這也是本文的重點 - Javadoc的Doclet和Taglet。

Doclet

Doclet是指決定Javadoc輸出格式的元件,也是一個Java程式,一般的我們看到的那種格式的HTML網頁就是使用Oracle提供的標準Doclet。JDK有提供Doclet API可以讓使用者自己客製化Javadoc的輸出,客製化的過程如下:

一、寫一個繼承com.sun.javadoc.Doclet的類別,這是一個位於JDK/lib/tools.jar中的抽象類別,有四個方法可以實作,分別是

  • static LanguageVersion languageVersion()
  • 回傳這個Doclet支援的Java版本
  • static int optionLength(String option)
  • 使用客製的Doclet時可能會傳入多個引數(option,如-tag)和其相對應的值,這個方法可回傳引數的長度(若該引數只有跟著一個值,則長度為二)。
  • static boolean start(RootDoc root)
  • 一定要實作的方法,在這裡決定文件輸出的格式,因為RootDoc是一個保存整個程式資訊的物件,可透過它得到程式設計師自行定義的類別、再進而得到當中相關的註解資料。
  • static boolean validOptions(String[] options, DocErrorReporter reporter)
  • 驗證引數的參數是否有效。
二、編譯寫好的Doclet類別,在編譯時要在classpath中增加JDK/lib下的tools.jar,Doclet API定義的類別和介面就存在於這個JAR中。

三、使用編譯好的Doclet類別,方法是在命令列中先輸入普通的javadoc指令再搭配-doclet 及-docletpath 兩個引數來指定我們要使用客製的Doclet而不是預設的。

要特別注意的是,若我們在自行定義的類別中有使用到不屬於JDK已有的類別時,必須在輸入Javadoc指令時將用到的Library以classpath引數設定進去,不然會有很多Cannot Find Symbol的警告。

Taglet

Taglet也是一個Java程式,JDK也有提供客製它的API,但Taglet的作用是讓我們自定標籤,可以將送進標籤內的字串做一些額外處理。

事實上,如果只是要使用一個不同名稱的標籤來界定不同的內容,似乎是不需要用到Taglet這個東西的,比較簡單的作法是在註解直接中使用自定名稱的標籤,然後透過Doclet API中Doc Interface定義的tags(String tagName)的方法來傳回該標籤的值,可以省去定義新標籤的麻煩。

標籤有分成Block tags(如@tag)和In-line tags(如{@tag})兩種形式,其中Block tags一定是用於每一行註解的開頭,它的註解內容可以是多行的字串,但不能包含另一個標籤;而In-line tags則可以用於任何文字可出現的地方。但不管是哪一種,因為Taglet API只有定義一個Interface,所以都是實作同一個界面。

客製化標籤的步驟如下:

一、寫一個實作Taglet Interface的類別,而且它會用到下列的類別
  import com.sun.tools.doclets.Taglet;          //Taglet API
  import com.sun.javadoc.*;             //Doclet API
  import java.util.Map;                //會用到這個資料結構
  要加入Doclet API的原因是要用到它當中定義的Tag Interface,透過這個介面可以得到標籤後面
  跟著的內容。
  Taglet Interface定義了十個方法,如下:
  String getName()                 //得到這個自定標籤的名稱
  boolean inConstructor()
  boolean inField()
  boolean inMethod()
  boolean inOverview()               //上面這些方法是用來規定
  boolean inPackage()                 //這個標籤能夠用在哪些部份的註解
  boolean inType()
  isInlineTag()                   //如果是Blogck tag就傳回False
  String toString(Tag tag)              //實作客製化動作的地方
  String toString(Tag[] tags)             //實作有多個Tag內容時的表現方式

二、實作一個public static void register(Map tagletMap)的方法使這個標籤的類別能在執行時被使用。

三、編譯已完成的Taglet,同樣地要設定JDK/lib/tools.jar給classpath引數。

四、使用自定的標籤,方法是在命令列中先輸入普通的Javadoc指令再加入-taglet 及-tagletpath 兩個引數讓Javadoc能認識新的標籤。

結語

原本的Javadoc功能就很強了,只是內建的Doclet有點太過於龐大,有時候明明只是一個小程式而已,產出的文件中最顯眼的是那大篇幅的空白,而且產出的內容似乎也缺少一點彈性,如果我們有能力決定文件內容要如何編排,並且使用自定的標籤來輔助文件的處理或甚至觸發別的動作,我想Javadoc會更可能直接用來當成撰寫系統開發文件的平台。

資料來源

Java安裝目錄下的文件,Javadoc的章節