S-JIS[2010-01-23/2015-12-28] 変更履歴

Ant独自タスクでのプロパティー使用方法

build.xml上に「${ }」でプロパティーを指定すると、属性(セッターメソッド)には、プロパティーが展開された値が入ってくる。
ただし、そのタスク実行時点でそのプロパティーに値が入っていない場合は、展開されずにそのまま入ってくる。

ボディー部にはプロパティーが展開されずに入ってくるので、必要であれば自分で展開する。


プロパティー関連メソッド

プロパティーの展開(置換)は、Project#replaceProperties()を使用する。

	String str = getProject().replaceProperties("置換元:${property}");

ただし、該当のプロパティーが無かった場合は変換されずにそのまま(${ }形式)で返ってくる。


プロパティーに値をセットするには、setNewProperty()を使用する。(Ant1.5以降)
このメソッドでは、既にプロパティーに値が入っている場合は(verboseレベルでメッセージ出力のみ行い、)値をセットしない。
(通常、Antでは、プロパティーの上書きや削除は行わない)
また、値がnullの場合も値は設定されない。(以前の値がそのまま残る)

	getProject().setNewProperty(name, value);

setProperty()を使うと、既に値が入っている場合でも値がセットされる。
(こちらも、値がnullの場合は何もしない)

	getProject().setProperty(name, value);

属性の例

属性のプロパティーを扱う例。

  事前にプロパティーがセットされている場合 事前にプロパティーがセットされていない場合
概要 独自タスク実行前にプロパティーがセットされている場合、
セッターメソッド呼び出し時点で展開されている。
独自タスク実行前にプロパティーがセットされていない場合、
セッターメソッドには展開前の形でそのまま入ってくる。
build.xml
<target name="〜">
	<property name="test" value="abc" />
	<sample attr="${test}" />
</target>
<target name="〜">

	<sample attr="${test}" />
</target>
SampleTask
public class SampleTask extends Task {

	protected String attr;

	public void setAttr(String s) {
		attr = s;
	}

	public void execute() throws BuildException {
		log(attr);

		log(getProject().replaceProperties(attr));
	}
}
public class SampleTask extends Task {

	protected String attr;

	public void setAttr(String s) {
		attr = s;
	}

	public void execute() throws BuildException {
		log(attr);
		getProject().setProperty("test", "def");
		log(getProject().replaceProperties(attr));
	}
}
出力例 abc
abc
${test}
def

ボディー部のテキストの例

ボディー部のテキストにはプロパティーが展開されずに入ってくるので、必要であれば自分で展開する。[2009-01-26]

SampleTask.java:

public class SampleTask extends Task {

	protected String text;

	public void addText(String s) {
		text = s;
	}

	public void execute() throws BuildException {
		log(text);
		log(getProject().replaceProperties(text));
	}
}

build.xml:

	<target name="text">
		<sample>Antパスは${ant.library.dir}です。</sample>
	</target>

実行結果:

Buildfile: C:\workspace\sample\bin\build.xml
text:
     [sample] Antパスは${ant.library.dir}です。
     [sample] AntパスはC:\eclipse\plugins\org.apache.ant_1.7.0.v200803061910\libです。
BUILD SUCCESSFUL
Total time: 203 milliseconds

PropertyHelper(Ant1.6)

Ant1.6からPropertyHelperというクラスが導入され、Projectクラスを使ったプロパティーの取得/設定はPropertyHelperに委譲されるようになった。

ProjectのsetProperty()・getProperty()の値はStringしか受け付けないが、PropertyHelperではObjectを使用できる。
ただしProject#getProperty()はPropertyHelper#getProperty()の戻り値を問答無用でStringにキャストしているので注意。

Ant1.6〜1.7のプロパティーにはフックという仕組みがある。(Ant1.8でフックの機能は使えなくなった。Delegateを使用する。[2015-12-28]
つまり、getProperty()が呼ばれた際に、自分で作ったメソッドを経由させることが出来る。
ここで独自の判定を行って値を返すようにすれば、setProperty()を呼んで値をセットしておかなくてもプロパティーの値が返せることになる。
使うかどうか分からない値を軒並み事前にセットしておくよりは、使うものだけを使う際に算出することで、効率が良くなると考えられる。
このフックの機能を実現しているのがPropertyHelper。

独自PropertyHelper.java

import org.apache.tools.ant.PropertyHelper;
public class MyPropertyHelper extends PropertyHelper {

	static final String PREFIX = "sample.";

	static Map<String, String> MAP = new HashMap<String, String>();
	static {
		MAP.put(PREFIX + "prop1", "値1");
		MAP.put(PREFIX + "prop2", "値2");
	}

	/**
	 * getProperty()の際に呼ばれるフック.
	 *
	 * @param ns
	 * @param name	プロパティー名
	 * @param user
	 */
	@Override
	public Object getPropertyHook(String ns, String name, boolean user) {
		if (name != null && name.startsWith(PREFIX)) {
			return MAP.get(name);
		}
		return super.getPropertyHook(ns, name, user);
	}
}

getProperty()で独自の値を返すには、PropertyHelperを継承したクラスを作り、getPropertyHook()をオーバーライドする。
上記の例では「sample.」で始まるプロパティー名を対象とし、「sample.prop1」の時は「値1」、「sample.prop2」の時は「値2」を返している。
super.getPropertyHook()を呼ぶと、後続のフック処理が実行される。つまり、通常のプロパティー取得処理が行われる。

独自タスククラス.java:

独自タスクの開始時に、自分のPropertyHelperを登録してやる。

import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
public class SampleTask extends Task {

	protected String attr;

	public void setAttr(String s) {
		attr = s;
	}

	@Override
	public void init() throws BuildException {
		initMyPropertyHelper();
	}

	@Override
	public void execute() throws BuildException {
//		initMyPropertyHelper();

		log("attr     = " + attr);
		log("attr[rep]= " + getProject().replaceProperties(attr));
	}

	void initMyPropertyHelper() {
		Project project = getProject();
		PropertyHelper rootHelper = PropertyHelper.getPropertyHelper(project);

		MyPropertyHelper helper = new MyPropertyHelper();
		helper.setProject(project);
		helper.setNext(rootHelper.getNext());	//自分の次のヘルパーに、今までのヘルパーを指定
		rootHelper.setNext(helper);		//自分のヘルパーを指定
	}
}

※setNext()によってヘルパーを追加する。したがって、何度もこのタスクが実行されると、どんどん同じヘルパーが追加されることになる…。
 別の箇所でヘルパーを追加しているクラスがあるかもしれないので、単純に自分の前のヘルパーを保持しておいて戻せばいいわけでもない。

build.xml:

	<target name="sample">
		<taskdef name="sample" classname="jp.hishidama.sample.ant.SampleTask" classpath="classes" />

		<sample attr="${sample.prop1}" />	←SampleTaskの実行(ここで独自のプロパティーヘルパーを設定)
		<echo message="${sample.prop1}" />
		<property name="sample.prop2" value="zzz" />
		<echo message="${sample.prop2}" />	←proprtyタスクで設定した値よりも、PropertyHelperで返す値の方が優先される
	</target>

実行結果:

ヘルパーをinit()で登録 ヘルパーをexecute()で登録
Buildfile: C:\workspace\sample\bin\build.xml
sample:
   [sample] attr     = 値1
   [sample] attr[rep]= 値1
     [echo] 値1
     [echo] 値2
BUILD SUCCESSFUL
Total time: 282 milliseconds
Buildfile: C:\workspace\sample\bin\build.xml
sample:
   [sample] attr     = ${sample.prop1}
   [sample] attr[rep]= 値1
     [echo] 値1
     [echo] 値2
BUILD SUCCESSFUL
Total time: 282 milliseconds

init()は属性の設定が行われる前(セッターメソッドが呼ばれる前)に実行されるので、
自分の属性にPropertyHelperで返すプロパティーをセットしておいてもその値が渡される。

自分のタスクより後のタスクでプロパティーを使うことを考えるならsetProperty()を呼んでおく方が素直だと思うが、
自分のタスクの属性でプロパティー名を指定して それを自分で使うような場合にはPropertyHelperを使うのが便利かも。


PropertyHelper(Ant1.8)

Ant1.8でPropertyHelperの仕様が変わり、Ant1.6のgetPropertyHook()やsetNext()/getNext()が使えなくなった。[2015-12-28]
PropertyHelperから独自のプロパティー値を返したい場合は、PropertyEvaluatorというクラスを作り、それをPropertyHelperに登録する。
(PropertyEvaluatorに限らず、PropertyHelperにDelegateを登録する形になった。PropertyEvaluatorもDelegateのひとつである)

import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
public class Example18Task extends Task {

	protected String attr;

	public void setAttr(String s) {
		attr = s;
	}

	@Override
	public void init() throws BuildException {
		initMyPropertyHelper();
	}

	@Override
	public void execute() throws BuildException {
		log("attr     = " + attr);
		log("attr[rep]= " + getProject().replaceProperties(attr));
	}

	void initMyPropertyHelper() {
		Project project = getProject();
		PropertyHelper helper = PropertyHelper.getPropertyHelper(project);

		MyPropertyEvaluator evaluator = new MyPropertyEvaluator();
		helper.add(evaluator); // 自分のdelegateをヘルパーに登録
	}
}

MyPropertyEvaluator.java:

import org.apache.tools.ant.PropertyHelper.PropertyEvaluator;
import org.apache.tools.ant.property.NullReturn;
public class MyPropertyEvaluator implaments PropertyEvaluator {

	static final String PREFIX = "example.";

	static Map<String, String> MAP = new HashMap<String, String>();
	static {
		MAP.put(PREFIX + "prop1", "値1");
		MAP.put(PREFIX + "prop2", "値2");
	}

	/**
	 * getProperty()の際に呼ばれるフック.
	 *
	 * @param name	プロパティー名
	 * @param propertyHelper
	 */
	@Override
	public Object evaluate(String name, PropertyHelper propertyHelper) {
		if (name != null && name.startsWith(PREFIX)) {
			String value = MAP.get(name);
			return (value != null) ? value : NullReturn.NULL;
		}
		return null;
	}
}

PropertyEvaluatorではevaluateメソッドを実装する。
このメソッドはPropetyHelperのgetPropertyメソッドの中から呼ばれるので、自分が処理する対象のプロパティーであれば、その値を返すようにする。

PropetyHelperには複数のDelegateが登録されるので、evaluateメソッドでnullを返すと、次のDelegateが呼ばれる。
自分の値としてのnullを返したい場合は、NullReturn.NULLを返せばよい。


独自タスクの作り方へ戻る / Ant目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま