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 |
${test} |
ボディー部のテキストにはプロパティーが展開されずに入ってくるので、必要であれば自分で展開する。[2009-01-26]
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));
}
}
<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
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。
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()を呼ぶと、後続のフック処理が実行される。つまり、通常のプロパティー取得処理が行われる。
独自タスクの開始時に、自分の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()によってヘルパーを追加する。したがって、何度もこのタスクが実行されると、どんどん同じヘルパーが追加されることになる…。
別の箇所でヘルパーを追加しているクラスがあるかもしれないので、単純に自分の前のヘルパーを保持しておいて戻せばいいわけでもない。
<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を使うのが便利かも。
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をヘルパーに登録
}
}
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を返せばよい。