How to write a generic java compile target in ant

The problem

We use ant for our builds and it generally works just fine. But we’ve been rationalising our many build scripts lately, identifying the common stuff and putting it into a common file. Obvious, really, and that is going well. In the process I came across an awkwardness, a kind of mismatch inside ant. We wanted a generic compile target that handles:

  1. running javac to compile the source files
  2. copying the non-java files (xml, xsd, xsl etc) across to the bin directory

We often have multiple source paths and javac lets you specify them like this:

javac srcdir=”java/src:java/test:java/other”

So I have three directories with source files. But when I want to copy them I have to say:

<copy todir=”${basedir}/bin” flatten=”no” >
  <fileset dir=”java/src” includes=”**/*.properties,**/*.xml”/>>
  <fileset dir=”java/test” includes=”**/*.properties,**/*.xml”/>
  <fileset dir=”java/other” includes=”**/*.properties,**/*.xml”/>>

Which would be okay but in different projects the list of source directories varies so I can’t have a generic target that will compile anything. Well, actually I can…

The Solution

First I need to have ant-contrib in my classpath, then I define the taskdef for it like this:

<taskdef resource=”net/sf/antcontrib/”/>

Once that is done I can make my generic target ehich looks like this:

<target name=”compile-source”>
        <delete dir=”${basedir}/bin” failonerror=”false”/>
        <mkdir dir=”${basedir}/bin”/>
        <javac destdir=”${basedir}/bin”  srcdir=”${srcpath}”>
                <path refid=”libs”/>
        <foreach delimiter=”:”
    <target name=”copysource”>
        <copy verbose=”true” todir=”${basedir}/bin” flatten=”no” >
            <fileset dir=”${d}” includes=”**/*.properties,**/*.xml”/>

The key to this is the foreach tag in the compile-source target. That loops through the srcpath, splitting out the colon delimited fields and running the copy.

It took me a while to figure out how to use foreach, so hopefully this is a help.


  1. We use ant for our builds and it generally works just fine. But we’ve been rationalising our many build scripts lately


    1. I have actually migrated everything to Maven since I wrote that post. Maven has two relevant advantages: 1) you can inherit common stuff from parent builds and 2) you can build maven plugins in Java and call them from your build. The latter seems like an ant task at first glance and it is, but maven is also a repository (like ant+ivy but more tightly integrated). So you specify your plugin in the maven build and you don’t have to do anything else for maven to go fetch it and its dependencies fro the repo.
      It took me a while to get around to moving to Maven but I would never go back… except in one or two places when I do call ant from maven because ant handles sequential scripts a little better.


Leave a Reply

Your email address will not be published. Required fields are marked *