AntUnit inside Maven

I’m in the middle of converting jslint4java to use maven as its build system (yes, really). Part of this is ensuring that the antunit tests I wrote continue to work. Maven has the antrun plugin, but it’s not 100% obvious how to use an antlib inside it.

Normally, to run an antlib extension as part of your build, you first dump the jar in ~/.ant/lib (or on the command line using a -lib flag) and then reference it in a namespace. e.g.

  <project name="foo"
           xmlns:au="antlib:org.apache.ant.antunit"></project>

This relies on ant being able to pick out org/apache/ant/antunit/antlib.xml from the classpath.

When doing this in maven through the antrun plugin, you can’t just dump stuff into ~/.ant/lib however. You need to tell ant where everything is. Originally, I was following the example of the rat ant task. This attempts to invoke a second copy of ant with the correct -lib argument. It’s ugly though. Why should we fork a second copy of the JVM? And ant may not even be installed (in maven, it’s just jar files in the local repository).

Eventually, I looked closer at the antlib documentation and found Load antlib from inside of the buildfile. This shows how a typedef is the key: You can associate a given antlib URI with a particular classpath entry. Thankfully, maven-antrun-plugin provides ${maven.test.classpath} (amongst others) which contains every entry that we need. So the solution now looks something like this.

Firstly, pom.xml.

  <project>
    <dependencies>
      <dependency>
        <groupId>org.apache.ant</groupId>
        <artifactId>ant-antunit</artifactId>
        <version>1.0</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
    <build>
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>test</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <tasks>
                <ant antfile="${build.testOutputDirectory}/antunit/tests.xml"
                  inheritAll="false" inheritRefs="false">
                  <property name="test.classpath" refid="maven.test.classpath" />
                </ant>
              </tasks>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <!-- Force an upgrade to a newer ant version.  Required by antunit. -->
          <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.7.0</version>
          </dependency>
        </dependencies>
      </plugin>
    </build>
  </project>

So, when we get to the test phase, we automatically run antunit/tests.xml, passing in the correct classpath. This is what the ant file looks like:

  <project name="jslint-antunit"
           xmlns:au="antlib:org.apache.ant.antunit">
 
      <taskdef uri="antlib:org.apache.ant.antunit"
               resource="org/apache/ant/antunit/antlib.xml"
               classpath="${test.classpath}" /></project>

This appears to work quite well, and runs my tests a sight quicker than before. If anybody from the apache rat project is listening, you might want to update your POMs. :)