プロパティ

プロパティは、Apache Antが実行時に${key}valueに展開しようとする、キーと値のペアです。

プロパティを設定できるタスクは多数ありますが、最も一般的なのはpropertyタスクです。さらに、プロパティはコマンドライン引数やAntの外部からの同様のメカニズムによって定義できます。

通常、プロパティの値は変更できません。プロパティが設定されると、ほとんどのタスクはその値の変更を許可しません。一般的に、プロパティはグローバルスコープを持ちます。つまり、一度定義されると、その後呼び出される任意のタスクまたはターゲットで使用できます。ただし、antantcallsubantタスクを使用して作成された子ビルドプロセスでプロパティを設定し、それを呼び出し元のビルドプロセスで使用できるようにすることはできません。

Ant 1.8.0以降localタスクを使用して、ターゲットまたはsequential要素(macrodefタスクのものなど)にローカルスコープのプロパティを作成できます。

組み込みプロパティ

Antは、<property>タスクを使用して定義されたかのように、すべてのシステムプロパティへのアクセスを提供します。たとえば、${os.name}はオペレーティングシステムの名前に展開されます。

システムプロパティのリストについては、System.getPropertiesのJavadocを参照してください。

さらに、Antにはいくつかの組み込みプロパティがあります。

basedir
プロジェクトのbasedirの絶対パス(<project>basedir属性で設定)。
ant.file
ビルドファイルの絶対パス。
ant.version
Antのバージョン。
ant.project.name
現在実行中のプロジェクトの名前。<project>name属性で設定されます。
ant.project.default-target
現在実行中のプロジェクトのデフォルトターゲットの名前。<project>default属性で設定されます。
ant.project.invoked-targets
現在のプロジェクトの呼び出し時に指定されたターゲット(コマンドライン、IDE内、<ant>タスクなど)のコンマ区切りのリスト。
このプロパティは、最初のターゲットが実行されるときに正しく設定されます。暗黙のターゲット(<project>タグの直下)で使用する場合、ターゲットが指定されていない場合はリストは空になり、ターゲット内にネストされたタスクの場合、プロジェクトのデフォルトターゲットが含まれます。
ant.java.version
Antが検出したJVMバージョン。現在、91.81.71.61.51.41.31.2の値を保持できます。
ant.core.lib
ant.jarファイルの絶対パス。

もう1つのプロパティもありますが、これはランチャースクリプトによって設定されるため、IDE内では設定されない場合があります。

ant.home
Antのホームディレクトリ。

次のプロパティは、ランチャー クラスを介して Ant が起動された場合にのみ設定されます(つまり、IDE 内でも設定されない場合があります)。

ant.library.dir
Antのjarのロードに使用されたディレクトリ。ほとんどの場合、これはANT_HOME/libです。

PropertyHelpers

Antのプロパティ処理は、現在のプロジェクトに関連付けられたorg.apache.tools.ant.PropertyHelperのインスタンスによって行われます。このクラスの詳細については、AntのJava APIを参照してください。Ant 1.8では、PropertyHelperクラスが大幅に改良され、プロパティの設定、取得、解析など、個別のタスクを処理するために、多くのヘルパークラス(実際にはorg.apache.tools.ant.PropertyHelper$Delegateマーカーインターフェースのインスタンス)を使用するようになりました。これにより、Antのプロパティ処理は非常に拡張性が高くなります。また、propertyhelperタスクは、AntビルドファイルのコンテキストからPropertyHelperとそのデリゲートを操作するために使用されるため、注目に値します。

Delegateには、実装に役立つ3つのサブインターフェースがあります。

デフォルトのPropertyExpanderは次のようになります。

public class DefaultExpander implements PropertyExpander {
    public String parsePropertyName(String s, ParsePosition pos,
                                    ParseNextProperty notUsed) {
        int index = pos.getIndex();
        if (s.indexOf("${", index) == index) {
            int end = s.indexOf('}', index);
            if (end < 0) {
                throw new BuildException("Syntax error in property: " + s);
            }
            int start = index + 2;
            pos.setIndex(end + 1);
            return s.substring(start, end);
        }
        return null;
    }
}

${toString:some-id}を現在のビルド内のidsome-idを持つオブジェクトの文字列表現に置き換えるロジックは、次のコードのようなPropertyEvaluatorに含まれています。

public class ToStringEvaluator implements PropertyHelper.PropertyEvaluator {
    private static final String prefix = "toString:";
    public Object evaluate(String property, PropertyHelper propertyHelper) {
        Object o = null;
        if (property.startsWith(prefix) && propertyHelper.getProject() != null) {
            o = propertyHelper.getProject().getReference(
                    property.substring(prefix.length()));
        }
        return o == null ? null : o.toString();
    }
}

プロパティ展開

Antが${some-text}という構成に出会うと、正確な解析セマンティクスは構成されたプロパティヘルパーデリゲートによって異なります。

$$展開

デフォルトの構成では、Antはテキスト$$を単一の$に展開し、その直後のテキストの通常のプロパティ展開メカニズムを抑止します。つまり、$${key}${key}に展開され、keyという名前のプロパティが定義されていて値がvalueであってもvalueには展開されません。これは、リテラル$文字をエスケープするために使用でき、プロパティ展開のように見える構成や、次のような診断出力を作成する場合に役立ちます。

<echo>$${builddir}=${builddir}</echo>

これは、次のメッセージを出力します。

${builddir}=build/classes

プロパティbuilddirの値がbuild/classesの場合。

古いAntリリースとの下位互換性を維持するために、プロパティのような構成(フランス語の中括弧のマッチしたペアを含む)とは別に遭遇した単一の$文字は、$としてそのまま解釈されます。「正しい」指定方法は、エスケープメカニズムを無条件で使用することです。そのため、$$$$$$を指定することで得られます。2つのアプローチを混在させると、$$$$$になるなど、予測できない結果になります。

中括弧のネスト

デフォルトの構成では、Antはプロパティ展開の中括弧のバランスを取ろうとしません。プロパティ名を作成する際、最初の中括弧までしかテキストを消費しません。つまり、${a${b}}のようなものを展開する場合、2つの部分に変換されます。

  1. プロパティa${bの展開(おそらく役に立たないもの)。
  2. 2番目の中括弧から生成されるリテラルテキスト}

つまり、名前がプロパティに格納されているプロパティを簡単に展開することはできませんが、古いバージョンのAntにはいくつかの回避策があります。Ant 1.8.0以降props Antlibを使用すると、このような機能が必要な場合は、そこに定義されているNestedPropertyExpanderを使用するようにAntを構成できます。

プロパティ参照の展開

最も単純な形式では、${key}keyという名前のプロパティを検索し、プロパティの値に展開する必要があります。ただし、追加のPropertyEvaluatorによって、keyの解釈が異なる場合があります。

props Antlibはいくつかの興味深い評価器を提供しますが、いくつかの組み込み評価器もあります。

${toString:}を使用した参照の値の取得

参照で宣言された任意のAntタイプのアイテムは、${toString:}操作を使用して文字列値を抽出することもでき、参照の名前がtoString:テキストの後にリストされます。参照されているJavaクラスインスタンスのtoString()メソッドが呼び出されます。すべての組み込みタイプは、このようなインスタンスで有用で関連性の高い出力を生成しようとします。

たとえば、fileset内のファイルのリストを取得する方法を次に示します。

<fileset id="sourcefiles" dir="src" includes="**/*.java"/>
<echo> sourcefiles = ${toString:sourcefiles} </echo>

外部タイプがそのような状況で意味のある情報を提供するという保証はありません。

${ant.refid:}を使用した参照の値の取得

参照で宣言された任意のAntタイプのアイテムは、${ant.refid:}操作を使用してプロパティとして使用することもでき、参照の名前がant.refid:テキストの後にリストされます。この操作と${toString:}の違いは、${ant.refid:}が参照されているオブジェクト自体に展開されることです。ほとんどの場合、toString()メソッドは呼び出されます。たとえば、${ant.refid:}が他のテキストで囲まれている場合などです。

この構文は、String以外のオブジェクトを受け入れる属性セッターを持つタスクを使用する場合に最も役立ちます。たとえば、セッターが次のようにResourceオブジェクトを受け入れる場合。

public void setAttr(Resource r) { ... }

構文を使用して、以前に参照として定義されたリソースサブクラスを渡すことができます。

<url url="https://ant.dokyumento.jp/" id="anturl"/>
<my:task attr="${ant.refid:anturl}"/>

If/Unless属性

<target> 要素と様々なタスク(<fail> など)およびタスク要素(<junit> 内の <test> など)は、if 属性と unless 属性をサポートしており、これらを使用してアイテムの実行または有効化の制御を行うことができます。

Ant 1.7.1以前では、これらの属性はプロパティ名のみを指定することができました。その名前のプロパティが定義されていれば(空文字列やfalseであっても)、アイテムは有効になり、プロパティが定義されていなければ無効になります。例えば、以下は動作しますが、ファイルの存在チェックを否定的に(肯定的にのみならず)上書きする方法はありません。

<target name="-check-use-file">
    <available property="file.exists" file="some-file"/>
</target>
<target name="use-file" depends="-check-use-file" if="file.exists">
    <!-- do something requiring that file... -->
</target>
<target name="lots-of-stuff" depends="use-file,other-unconditional-stuff"/>

Ant 1.8.0以降、プロパティ展開を使用できるようになりました。true(またはonyes)の値はアイテムを有効にし、false(またはoffno)はアイテムを無効にします。それ以外の値は依然としてプロパティ名とみなされ、そのため、指定された名前のプロパティが定義されている場合のみ、アイテムは有効になります。

従来の方法と比較して、コマンドラインや親スクリプトから条件を上書きできるため、柔軟性が向上します。

<target name="-check-use-file" unless="file.exists">
    <available property="file.exists" file="some-file"/>
</target>
<target name="use-file" depends="-check-use-file" if="${file.exists}">
    <!-- do something requiring that file... -->
</target>
<target name="lots-of-stuff" depends="use-file,other-unconditional-stuff"/>

これで、ant -Dfile.exists=false lots-of-stuff を実行すると、予想通りother-unconditional-stuff は実行されますが、use-file は実行されません。他のスクリプトからも条件を無効化できます。

<antcall target="lots-of-stuff">
    <param name="file.exists" value="false"/>
</antcall>

同様に、unless 属性は、定義されているプロパティの名前である場合、またはtrueのような値に評価される場合に、アイテムを無効にします。例えば、以下のようにmy-prefs.propertiesskip.printing.message=trueを定義すると、期待通りの結果が得られます。

<property file="my-prefs.properties"/>
<target name="print-message" unless="${skip.printing.message}">
    <echo>hello!</echo>
</target>