Ant Patterns

Ant is a common build tool with very extensive documentation. It is still widely used and I recommend this tool for automating file system heavy steps. You can even call Ant tasks directly in Groovy using the AntBuilder which brings you an extremely powerful and well documented API without any hustle.

Here I have gathered a few Ant Patterns that you should be aware of when you build an Ant script.

Presence Validator for Properties

The properties can be loaded from a properties file, xml file or set directly using the property task. A property can only be defined once and cannot be overridden as it has the semantics of a final constant.

To ensure that a property is set, you can use the fail task to abort unless the property has been defined beforehand.

<fail unless="property.key"/>
<echo message="property.key = ${property.key}"/>

However, failing without a message makes the error very hard to come by. Therefore, the message attribute should be used to indicate the failure reason.

<fail message=""the property property.key is not defined" unless="property.key"/>
<echo message="property.key = ${property.key}"/>

If there are many property checks in a build file, these two lines have to be duplicated for every property to check. Much better is the use of a macrodef task which is basically a custom task with private properties named attributes.

<!-- definition of validate-presence-of-property task -->
<macrodef name="validate-presence-of-property">
       <attribute name="propertyKey"/>
       <sequential>
               <fail message="the property @{propertyKey} is not defined" unless="@{propertyKey}"/>
               <echo message="@{propertyKey} = ${@{propertyKey}}"/>
       </sequential>
</macrodef>

<!-- usage of the macrodef -->
<validate-presence-of-property propertyKey="my.property" />

The @{propertyKey} resolves to the given attribute value, in the example above to my.property. If you need the value of my.property, you have to evaluate it using the standard evaluation mechanism ${@{propertyKey}}.

The presented solution has been adapted from this presentation. This pattern can be reused for validate the presence of files, folders and the like using arbitrary conditions.

Default Values for Properties

A very common use case is to define a property with a default value and let the user override that value with a property file. As a property can only be initialized once, we can use this to implement this very simple by importing the properties from a file and try to set the properties to their default values afterwards. Setting the default value will fail (without an error) in case the property already exists.

<!-- include properties from file -->
<property file="my.properties"/>

<!-- set defaults which are only set if the properties do not already exist -->
<property name="some.property" value="default-value"/>

Updating/Removing Itself

Ant can delete/modify its own build file. This can be useful if you want to update the build file with an update target. A use case for this is to generate the build.xml from another xml file via xslt as I have implemented it in this project. In that case, I generate the build.xml from the manifest.xml of a Joomla extension.

<!-- updating using a stylesheet -->
<xslt in="manifest.xml" out="build.xml" style="some-stylesheet.xsl" force="true"/>
<!-- removing -->
<delete file="build.xml"/>

For this pattern, I was inspired by this blog post which shows that ant can delete itself.

Executing Platform Independent

Executing commands on the command line with ant can be problematic with the exec task. Under linux or Mac OSX you can execute the command directly while you need to prepend cmd /c under Windows as described here. Because the scripts should be platform independent, you can make use of the osfamily attribute of the exec task which executes the task only if the operating system matches the given osfamily.

<exec executable="cmd" osfamily="windows">
     <arg value="/c"/>
     <arg value="ruby"/>
     <arg value="-v"/>
</exec>
<exec executable="ruby" osfamily="unix">
     <arg value="-v"/>
</exec>

However, I you need to call several commands on the command line, you get code duplication. Macrodef to the rescue.

<!-- macro for executing a command plattform independent -->
<macrodef name="execute">
       <attribute name="executable"/>
       <element name="args" implicit="yes"/>
       <sequential>
                <exec osfamily="windows" executable="cmd">
                       <arg value="/c"/>
                       <arg value="@{executable}"/>
                       <args/>
                </exec>
                <exec osfamily="unix" executable="@{executable}">
                       <args/>
               </exec>
      </sequential>
</macrodef>

<!-- usage -->
<execute executable="ruby">
    <arg value="-v"/>
</execute>

Simple Usage Information

Most tools provide usage information when called without parameter. As we want to write self-documenting code, you can use the ant -p or ant -projecthelp commands which print all targets which have the description attribute set on the console. We can let Ant call itself via command line as shown in the following listing:

<project name="test" default="usage">
     <target name="usage" description="usage information">
        <exec executable="cmd">
            <arg value="/c"/>
            <arg value="ant"/>
            <arg value="-p"/>
        </exec>
    </target>
</project>

It is important to set the default attribute of the project to usage to call the usage target when no targets are specified.

You can combine the pattern Executing Platform Independet with this to get the following ant script:

<project name="test" default="usage">
     <target name="usage" description="usage information">
        <execute executable="ant">
            <arg value="-p"/>
        </execute>
    </target>
</project>

More about printing usage information in Ant can be found here.

Collection of Links for Other Useful Ant Tipps

The Java Initializers

In Java, the concepts of classes and instances are the core concepts. A class as well as each instance has variables and methods. To differentiate, the variables and methods corresponding to the class have to be marked static while variables and methods default to the instance (if not marked static). In the following, I focus only on the variables.

The following example shows the declaration for class and instance variables:

public class Variables {
  static String classVariable; // initialized with default value null

  String instanceVariable; // initialized with default value null
}

Class Variables

Class variables are interpreted in the order they appear in the file. I can directly assign values to a class variable (direct initialization) or call a static method which initialises the variable through its return value. This, however, can lead to problems as shown in the next listing:

public class Variables {
  static String directlyInitialized = "class variable";
  static String directlyInitializedWithMethod = init();
  static String anotherDirectlyInitialized = "test";

  private static String init() {
    return anotherDirectlyInitialized;
  }

  public static void main(String[] args) {
    System.out.println(directlyInitializedWithMethod); // prints null
  }
}

This will print out null as the variable anotherDirectlyInitialized is initialized after the directlyInitializedWithMethod is initialized. The compiler does not detect it, it is the responsibility of the programmer to avoid such situations. We could solve this issue by reordering the statements, however, this is an area where we can do errors easily.

There is another alternative, namely, class initializers. These initializers are executed after all static variables have been initialized.

public class Variables {
  static String directlyInitialized = "class variable";
  static String directlyInitializedWithMethod;
  static String anotherDirectlyInitialized = "test";

  static {
    directlyInitializedWithMethod = anotherDirectlyInitialized;
  }

  public static void main(String[] args) {
    System.out.println(directlyInitializedWithMethod); // prints test
  }
}

This static block can contain any complex setup logic. It is executed after all static variables are initialised but before any method call to the class is issued. Good use cases are the computation of constants or preinitialization of other instances which require more than a simple constructor or method call.

Instance Variables

The approach of initializing static variables is also applied to instance variables. I can directly assign values to an instance variable (direct initialization) or call a method which initialises the variable through its return value. This, however, can lead to the same initialization problems.

public class Variables {
  String directlyInitialized = "class variable";
  String directlyInitializedWithMethod = init();
  String anotherDirectlyInitialized = "test";

  private String init() {
    return anotherDirectlyInitialized;
  }

  public static void main(String[] args) {
    InstanceVariables object = new InstanceVariables();
    System.out.println(object.directlyInitializedWithMethod); // prints null
  }
}

However, there is also an initializer construct for instance variables. This construct is called before any constructor is called and allows to initialize instance variables regardless of their ordering.

public class Variables {
  String directlyInitialized = "class variable";
  String directlyInitializedWithMethod;
  String anotherDirectlyInitialized = "test";

  {
    directlyInitializedWithMethod = anotherDirectlyInitialized;
  }

  public static void main(String[] args) {
    InstanceVariables object = new InstanceVariables();
    System.out.println(object.directlyInitializedWithMethod); // prints test
  }
}

Another real use case of these instance initializers is to add values to a HashMap on creation as seen in the next code snippet:

// regular approach
Map<String, String> myMap = new HashMap<>();
myMap.put("DE", "German");
myMap.put("EN", "English");
		
		
Map<String, String> otherMap = new HashMap<String, String>() {
	// anonymous subclass of HashMap

	{
		// instance initializer setting specific values
		this.put("DE", "German");
		this.put("EN", "English");
	}

};

The advantage is, that the latter can be used to initialize a field in a class directly with specific values.

Initializing Arrays in Java

Arrays are widely used in many (almost any) programming languages. In Java, you have to specific the length of an Array at the creation of an Array.

Here is a short example how to initalize an Array containting the numbers 1, 2 and 3:

int[] numbers = new int[3];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;

In order to abbreviate this, there is a short form which can do this work in one line. This works as Java can determine the length of the array by looking at the number of elements within the curly brackets. At compile time, the short form is translated to the form above within the byte code.

int[] numbers2 = {1,2,3};

Now, there are some quirks to be aware of regarding the short form. You can use this only while defining the array variable. The following will result in a compile error:

int[] numbers2 = {1,2,3};
numbers2 = {4,5,6}; // compile error!

Why does this happen? The error message says: “Array constants can only be used in initializers”. But I am not quite sure, what the meaning behind is. I consider it a quirk of the Java language without any further research regarding this construct. 😉

However, today, I found a trick to circumvent this issue. You can find the solution in the Oracle Java Magazine, Section Fix This.

int[] numbers3 = {1,2,3};
numbers3 = new int[]{4,5,6};

I am not quite sure, why this works. Do you?