自訂元件

概觀

自訂元件是 Apache Ant 核心外部定義的條件、選擇器、篩選器和其他物件。

在 Ant 1.6 中,自訂條件、選擇器和篩選器已進行大修。

現在可以定義表現得像 Ant Core 元件的自訂條件、選擇器和篩選器。這能透過允許在建置指令碼中定義的資料類型,在資料類別相容或已由轉接器類別轉接時,用作自訂元件來達成。

定義自訂元件的舊方法仍受支援。

定義和使用

自訂元件是實作特定介面或延伸特定類別,或已轉接至介面或類別的正常 Java 類別。

這完全就像撰寫 自訂工作。透過撰寫 設定器 方法和 新增 方法來定義屬性和巢狀元素。

在撰寫類別後,會使用 <typedef> 將其新增至 ant 系統。

自訂條件

自訂條件是實作 org.apache.tools.ant.taskdefs.condition.Condition 的資料類型。例如,如果字串全部為大寫,則會傳回 true 的自訂條件可以撰寫成

package com.mydomain;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.condition.Condition;

public class AllUpperCaseCondition implements Condition {
    private String value;

    // The setter for the "value" attribute
    public void setValue(String value) {
        this.value = value;
    }

    // This method evaluates the condition
    public boolean eval() {
        if (value == null) {
            throw new BuildException("value attribute is not set");
        }
        return value.toUpperCase().equals(value);
    }
}

將條件新增至系統的方式如下

<typedef
    name="alluppercase"
    classname="com.mydomain.AllUpperCaseCondition"
    classpath="${mydomain.classes}"/>

現在可以在使用 Core Ant 條件的任何地方使用此條件。

<condition property="allupper">
    <alluppercase value="THIS IS ALL UPPER CASE"/>
</condition>

自訂選擇器

自訂選擇器是實作 org.apache.tools.ant.types.selectors.FileSelector 的資料類型。

只有一個必要的方法 public boolean isSelected(File basedir, String filename, File file)。它會根據是否應該選擇指定的檔案,傳回 true 或 false。

選擇以 .java 結尾的檔名的自訂選擇範例如下

package com.mydomain;
import java.io.File;
import org.apache.tools.ant.types.selectors.FileSelector;
public class JavaSelector implements FileSelector {
    public boolean isSelected(File b, String filename, File f) {
        return filename.toLowerCase().endsWith(".java");
    }
}

將選擇器新增至系統的方式如下

<typedef
    name="javaselector"
    classname="com.mydomain.JavaSelector"
    classpath="${mydomain.classes}"/>

現在可以在使用 Core Ant 選擇器的任何地方使用此選擇器,例如

<copy todir="to">
    <fileset dir="src">
        <javaselector/>
    </fileset>
</copy>

可以使用 org.apache.tools.ant.types.selectors.BaseSelector,這是一個提供合理預設行為的便利類別。它有一些預先定義的行為可以利用。每次在設定屬性或新增標籤時遇到問題,都可以呼叫 setError(String errmsg),而類別就會知道有問題。然後,在 isSelected() 方法的頂端呼叫 validate(),並會擲回一個 BuildException,其內容包含錯誤訊息。validate() 方法也會提供最後一次機會檢查設定的一致性,因為它會呼叫 verifySettings()。覆寫這個方法,並在其中呼叫 setError(),如果你偵測到選擇器設定有任何問題。

要撰寫自訂選擇器容器,應該延伸 org.apache.tools.ant.types.selectors.BaseSelectorContainer。實作 public boolean isSelected(File baseDir, String filename, File file) 方法來執行正確的動作。你可能會想要迭代底下的選擇器,因此使用 selectorElements() 來取得一個執行此動作的迭代器。

例如,要建立一個選擇器容器,如果包含的特定數量的選擇器選取,它就會選取檔案,可以撰寫一個選擇器如下

public class MatchNumberSelectors extends BaseSelectorContainer {
    private int number = -1;
    public void setNumber(int number) {
        this.number = number;
    }
    public void verifySettings() {
        if (number < 0) {
           throw new BuildException("Number attribute should be set");
        }
    }
    public boolean isSelected(File baseDir, String filename, File file) {
        validate();
        int numberSelected = 0;
        for (Enumeration e = selectorElements(); e.hasNextElement();) {
            FileSelector s = (FileSelector) e.nextElement();
            if (s.isSelected(baseDir, filename, file)) {
                numberSelected++;
            }
        }
        return numberSelected == number;
    }
}

要定義和使用這個選擇器,可以執行

<typedef name="numberselected"
         classname="com.mydomain.MatchNumberSelectors"/>
...
<fileset dir="${src.path}">
    <numberselected number="2">
        <contains text="script" casesensitive="no"/>
        <size value="4" units="Ki" when="more"/>
        <javaselector/>
    </numberselected>
</fileset>

自訂選擇器

自訂選擇器是 Ant 1.6 之前定義自訂選擇器的方法。此方法仍然支援,以維持向下相容性。

可以在選擇器容器中撰寫自己的選擇器並使用它們,方法是在 <custom> 標籤中指定它們。

要建立新的自訂選擇器,必須建立一個實作 org.apache.tools.ant.types.selectors.ExtendFileSelector 的類別。最簡單的方法是透過便利基礎類別 org.apache.tools.ant.types.selectors.BaseExtendSelector,它提供所有支援 <param> 標籤的方法。首先,覆寫 isSelected() 方法,並選擇性地覆寫 verifySettings() 方法。如果自訂選擇器需要設定參數,也可以覆寫 setParameters() 方法,並以任何喜歡的方式詮釋傳入的參數。幾個核心選擇器示範如何執行此動作,因為它們也可以用作自訂選擇器。

一旦撰寫完成,就可以使用 <custom> 標籤將它包含在建置檔案中。

屬性 說明 必要
classname 實作 org.apache.tools.ant.types.selectors.FileSelector 的類別名稱。
classpath 用於載入自訂選擇器類別的類別路徑。如果未指定 classpathclasspathref,則會從 Ant 使用的類別路徑載入類別。
classpathref 先前已定義的類別路徑參考。如果未指定上述 classpathrefclasspath,則會從 Ant 使用的類別路徑載入類別。

以下是如何使用 <custom> 將類別用作選擇器

<fileset dir="${mydir}" includes="**/*">
    <custom classname="com.mydomain.MySelector">
        <param name="myattribute" value="myvalue"/>
    </custom>
</fileset>

核心選擇器也可以用作自訂選擇器

以下是 Depth Selector 區段的範例,改寫為透過 <custom> 使用選擇器。

<fileset dir="${doc.path}" includes="**/*">
    <custom classname="org.apache.tools.ant.types.selectors.DepthSelector">
        <param name="max" value="1"/>
    </custom>
</fileset>

選取基底目錄和其下一個目錄中的所有檔案。

自訂篩選器讀取器

自訂篩選器讀取器選擇器是實作 org.apache.tools.ant.types.filters.ChainableReader 的資料類型。

只有一個必要的方法,Reader chain(Reader reader)。這會傳回一個篩選指定讀取器輸入的讀取器。

例如,移除每一個第二個字元的篩選器讀取器可以是

public class RemoveOddCharacters implements ChainableReader {
    public Reader chain(Reader reader) {
        return new BaseFilterReader(reader) {
            int count = 0;
            public int read() throws IOException {
                while (true) {
                    int c = in.read();
                    if (c == -1) {
                        return c;
                    }
                    count++;
                    if ((count % 2) == 1) {
                        return c;
                    }
                }
            }
        }
    }
}

對於以行為導向的篩選器,延伸 ChainableFilterReader,也就是 org.apache.tools.ant.filters.TokenFilter 的內部類別,可能會比較容易。

例如,附加行號的篩選器可以是

public class AddLineNumber extends ChainableReaderFilter {
    private void lineNumber = 0;
    public String filter(String string) {
        lineNumber++;
        return "" + lineNumber + "\t" + string;
    }
}