Tuesday, August 20, 2013

Ant Properties Nuances

Every once in a while, I'm reminded of a few subtle nuances of Ant properties that can, when forgotten, lead to confusion when dealing with Ant. In particular, the fact that Ant properties are generally immutable (not counting local properties as of Ant 1.8) and are set "permanently" upon their first setting can lead to slightly surprising results.

The properties section of the Ant Manual states, "Normally property values can not be changed, once a property is set, most tasks will not allow its value to be modified." The section of that manual on the Property task adds, "Properties are immutable: whoever sets a property first freezes it for the rest of the build; they are most definitely not variables."

The order of definition of properties influences their setting. In general, once a property is set, its value cannot be changed by a later attempt at redefinition in the same build file or in called build files. Furthermore, there are a set of properties that are already defined that generally cannot be redefined within an Ant build file. These include Java System properties and the built-in Ant properties.

Although definition of properties within an Ant build file cannot override the values of the default Ant built-in properties or the Java system properties, these values for these properties' names can generally be set with the -D option on the Ant launcher. However, a small number of these cannot be reset even with the -D option. For example, ant.file cannot be changed from the path and name of the Ant build file even when passed as a parameter via the -D option. Of course, it's probably just as well because there seems to be no good reason to pretend that the Ant build file is any other than what it really is.

To demonstrate the above "rules" of Ant property resolution, the following simple Ant build file can be used.

build.xml Displaying Properties in Ant
<project name="Project" default="showProperties" basedir=".">

   <property environment="env"/>
   
   <target name="showProperties">
      <!-- Java System Properties -->
      <echo message="java.home: ${java.home}" />
      <echo message="user.home: ${user.home}" />
      <!-- Custom Properties -->
      <echo message="name.last: ${name.last}" />
      <echo message="name.first: ${name.first}" />
      <!-- Ant Built-in Properties -->
      <echo message="ant.file: ${ant.file}" />
      <echo message="ant.version: ${ant.version}" />
      <echo message="ant.java.version: ${ant.java.version}" />
   </target>

</project>

There are a couple of Java system properties, a couple of custom properties, and a few Ant built-in properties in this example. These allow me to easily demonstrate how properties can be overridden or not overridden. The next screen snapshot shows the "default" settings of the properties without being overridden. The two custom ones are not defined at all, but the others (Java system and Ant built-in properties) have values automatically set for the Ant build.

The next screen snapshot shows an attempt to supply the values for the properties used in the build by passing them in via the -D parameters. As the example shows, even the system properties and Ant built-in properties can be overridden with the -D property setting, but the ant.file property is not overridden.

A common way to specify properties used in an Ant file are to specify them within the Ant build file using the Property task. The next code listing adds internally defined properties to the file shown above.

build.xml Defining Properties Internally
<project name="Project" default="showProperties" basedir=".">

   <property environment="env"/>
   <property name="user.home" value="/bin" />
   <property name="java.home" value="java" />
   <property name="name.last" value="Flintstone" />
   <property name="name.first" value="Fred" />
   <property name="ant.file" value="text.txt" />
   <property name="ant.version" value="1.8." />
   <property name="ant.java.version" value="6" />

   <target name="showProperties">
      <!-- Java System Properties -->
      <echo message="java.home: ${java.home}" />
      <echo message="user.home: ${user.home}" />
      <!-- Custom Properties -->
      <echo message="name.last: ${name.last}" />
      <echo message="name.first: ${name.first}" />
      <!-- Ant Built-in Properties -->
      <echo message="ant.file: ${ant.file}" />
      <echo message="ant.version: ${ant.version}" />
      <echo message="ant.java.version: ${ant.java.version}" />
   </target>

</project>

The next screen snapshot shows running this Ant file without any properties provided with the -D arguments. Note that the only properties which have been successfully set by the internal specification are the custom properties. The Java system properties and built-in Ant properties are unaffected by the attempts to internally set the properties.

There are advantages to Ant's properties generally being immutable. However, one must be cautious when assuming just because a property is declared in a particular Ant build file (or in a property file referenced by that build file), that it is actually the value to which that property is set for the build. If the property has already been set elsewhere, the local attempt at redefining the property has no effect other than to falsely advertise a value for that property which does not actually apply.

No comments: