屬性是 Apache Ant 在執行期間嘗試將 ${key}
擴充為 value
的鍵值對。
有許多任務可以設定屬性;最常見的是 property 任務。此外,屬性也可以透過 命令列參數 或 Ant 外部的類似機制定義。
通常屬性值無法變更:一旦設定屬性,大多數任務都不允許修改其值。一般而言,屬性屬於全域範圍,亦即一旦定義屬性,後續呼叫的任何任務或目標都可以使用該屬性—不過,無法在透過 ant、antcall 或 subant 任務建立的子建置程序中設定屬性,並讓呼叫建置程序使用該屬性。
自 Ant 1.8.0 起,local 任務可用於建立屬性,這些屬性是局部範圍,適用於目標或 sequential 元素,例如 macrodef 任務的元素。
Ant 提供對所有系統屬性的存取,就像使用 <property>
任務定義這些屬性一樣。例如,${os.name} 會擴充為作業系統名稱。
如需系統屬性清單,請參閱 System.getProperties 的 javadoc。
此外,Ant 有一些內建屬性
basedir
ant.file
ant.version
ant.project.name
<project>
的 name 屬性中設定。ant.project.default-target
<project>
的 default 屬性設定。ant.project.invoked-targets
<ant>
任務中等等)。<project>
標籤下方),如果未指定目標,清單將為空;如果已指定目標,則在此情況下,清單將包含專案的預設目標,適用於嵌套在目標中的任務。ant.java.version
9、
1.8、
1.7、
1.6、
1.5、
1.4、
1.3和
1.2。
ant.core.lib
還有一個屬性,但這是由啟動器腳本設定的,因此可能未在 IDE 內部設定
ant.home
如果透過 Launcher 類別啟動 Ant,才會設定下列屬性(表示 IDE 內部可能不會設定)
ant.library.dir
Ant 的屬性處理是由與目前專案相關聯的 org.apache.tools.ant.PropertyHelper
實例完成。你可以透過檢查 Ant 的 Java API 來深入了解這個類別。在 Ant 1.8 中,PropertyHelper
類別經過大幅修改,現在本身採用許多輔助類別(實際上是 org.apache.tools.ant.PropertyHelper$Delegate
標記介面的實例)來處理個別任務,例如屬性設定、擷取、剖析等。這使得 Ant 的屬性處理高度可擴充;另一個重點是新的 propertyhelper 任務,用於從 Ant 建置檔的內容處理 PropertyHelper 及其委派。
有三個 Delegate
子介面可能有助於實作
org.apache.tools.ant.property.PropertyExpander
主要負責在字串中找出屬性名稱(預設會從 ${foo} 中萃取 foo)。
如果你想發明自己的屬性語法,或是允許巢狀屬性擴充(因為預設實作不會平衡大括弧),就會實作這個介面(請參閱 NestedPropertyExpander
in the props Antlib 以取得範例)。
org.apache.tools.ant.PropertyHelper$PropertyEvaluator
用於將 ${some-string} 擴充為 Object
。
如果你想提供自己的儲存空間,且獨立於 Ant 的專案實例,就會實作這個介面,這個介面代表讀取端。一個範例是 org.apache.tools.ant.property.LocalProperties
,它實作 local properties 的儲存空間。
實作這個介面的另一個原因是,如果你想提供自己的「屬性通訊協定」,例如透過查詢專案參考 foo 並在其中呼叫 toString()
來擴充 toString:foo
(Ant 已實作,請參閱下方)。
org.apache.tools.ant.PropertyHelper$PropertySetter
負責設定屬性。
如果你想提供自己的儲存空間,且獨立於 Ant 的專案實例,就會實作這個介面,這個介面代表寫入端。一個範例是 org.apache.tools.ant.property.LocalProperties
,它實作 local properties 的儲存空間。
org.apache.tools.ant.PropertyHelper$PropertyEnumerator
負責列舉屬性名稱。
如果您想要提供獨立於 Ant 專案實例的儲存空間,則這是您要實作的介面,此介面代表讀取端的一部分。範例為 org.apache.tools.ant.property.LocalProperties
,它實作 local properties 的儲存空間。
此介面已新增至 Ant 1.10.9。
預設的 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} 替換為目前建置中具有 id some-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},而不是 value
,即使已定義名稱為 key
且值為 value 的屬性。這可以用來跳脫文字 $
字元,並在看起來像屬性擴充的結構中或當您想要提供診斷輸出時很有用,例如
<echo>$${builddir}=${builddir}</echo>
這會顯示此訊息
${builddir}=build/classes
如果屬性 builddir
的值為 build/classes。
為了維持與舊版 Ant 版本的相容性,會將單一 $
字元(除了屬性結構,包括一對匹配的花括號)解釋為文字,也就是 $
。不過,指定此文字字元的「正確」方式是無條件使用跳脫機制,因此 $$
是透過指定 $$$$
取得的。混合這兩種方法會產生無法預測的結果,因為 $$$
會產生 $$
。
在預設組態中,Ant 不會嘗試平衡屬性擴充中的大括弧,在建立屬性名稱時,它只會使用到第一個閉合大括弧之前的文字。例如,當擴充類似 ${a${b}} 的內容時,它會轉換成兩個部分
這表示您無法輕易地擴充儲存在屬性中的屬性名稱,但對於舊版的 Ant,有一些 解決方法。自 Ant 1.8.0 起,如果您需要此功能,可以使用 props Antlib,將 Ant 設定為使用其中定義的 NestedPropertyExpander
。
在最簡單的形式中,${key} 應尋找名為 key
的屬性,並擴充為該屬性的值。不過,其他 PropertyEvaluator
可能會對 key
有不同的詮釋。
props Antlib 提供一些有趣的評估器,但也有一些內建的評估器。
任何已宣告為參照的 Ant 類型項目,也可以使用 ${toString:} 操作來擷取其字串值,參照的名稱列在 toString:
文字之後。會呼叫所參照的 Java 類別實例的 toString()
方法,所有內建類型都會盡力在這種情況下產生有用且相關的輸出。
例如,以下是取得檔案集中的檔案清單的方法
<fileset id="sourcefiles" dir="src" includes="**/*.java"/> <echo> sourcefiles = ${toString:sourcefiles} </echo>
無法保證外部類型在這種情況下會提供有意義的資訊
任何已宣告為參照的 Ant 類型項目,也可以使用 ${ant.refid:} 操作作為屬性,參照的名稱列在 ant.refid:
文字之後。此操作與 ${toString:} 的差異在於,${ant.refid:} 會擴充為參照的物件本身。在大部分情況下,toString()
方法仍會被呼叫,例如,如果 ${ant.refid:} 被其他文字包圍。
當使用接受 String
以外物件的屬性設定器時,此語法最為有用。例如,如果設定器接受 Resource
物件,如下所示
public void setAttr(Resource r) { ... }
那麼語法可以用來傳入先前定義為參照的資源子類別,如下所示
<url url="https://ant.dev.org.tw/" id="anturl"/> <my:task attr="${ant.refid:anturl}"/>
<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
(或 on
或 yes
)的值將啟用項目,而 false
(或 off
或 no
)的值將停用項目。其他值仍假設為屬性名稱,因此只有在定義了已命名屬性的情況下才會啟用項目。
與舊式相比,這提供了額外的彈性,因為您可以從命令列或父指令碼覆寫條件
<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.properties 中定義 skip.printing.message=true
,並產生您可能預期的結果
<property file="my-prefs.properties"/> <target name="print-message" unless="${skip.printing.message}"> <echo>hello!</echo> </target>