自定义组件

概述

自定义组件是在 Apache Ant 核心之外定义的条件、选择器、过滤器和其他对象。

在 Ant 1.6 中,自定义条件、选择器和过滤器已经过全面修改。

现在可以定义行为类似于 Ant 核心组件的自定义条件、选择器和过滤器。这是通过允许在构建脚本中定义的数据类型用作自定义组件来实现的,前提是数据类型的类是兼容的,或者已被适配器类适配。

仍然支持定义自定义组件的旧方法。

定义和使用

自定义组件是一个普通的 Java 类,它实现特定的接口或扩展特定的类,或者已适应该接口或类。

这与编写 自定义任务 完全一样。通过编写setter方法和add方法来定义属性和嵌套元素。

编写完类后,使用<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}"/>

现在,可以在使用核心 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}"/>

现在,可以在使用核心 Ant 选择器的任何地方使用此选择器,例如

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

可以使用 org.apache.tools.ant.types.selectors.BaseSelector,这是一个提供合理默认行为的便利类。它有一些你可以利用的预定义行为。在设置属性或添加标签时遇到问题时,可以调用 setError(String errmsg),该类将知道存在问题。然后,在你的 isSelected() 方法的顶部调用 validate(),将抛出包含错误消息内容的 BuildExceptionvalidate() 方法还为你提供了最后一次机会来检查设置的一致性,因为它调用了 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 用于加载自定义选择器类的类路径。如果既未指定 classpath 也未指定 classpathref,则该类将从 Ant 使用的类路径加载。
classpathref 对先前定义的类路径的引用。如果既未指定 classpathref 也未指定上面的 classpath,则该类将从 Ant 使用的类路径加载。

以下是使用 <custom> 将你的类用作选择器的方法

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

也可以用作自定义选择器的核心选择器是

以下是深度选择器部分的示例,已重写为通过 <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;
                    }
                }
            }
        }
    }
}

对于面向行的过滤器,扩展 ChainableFilterReaderorg.apache.tools.ant.filters.TokenFilter 的内部类)可能更容易。

例如,一个在行尾追加行号的过滤器可以是

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