Gradle provides excellent integration with Ant. You can use individual Ant tasks or entire Ant builds in your Gradle builds. In fact, you will find that it’s far easier and more powerful using Ant tasks in a Gradle build script, than it is to use Ant’s XML format. You could even use Gradle simply as a powerful Ant task scripting tool.

Ant can be divided into two layers. The first layer is the Ant language. It provides the syntax for the build.xml file, the handling of the targets, special constructs like macrodefs, and so on. In other words, everything except the Ant tasks and types. Gradle understands this language, and allows you to import your Ant build.xml directly into a Gradle project. You can then use the targets of your Ant build as if they were Gradle tasks.

The second layer of Ant is its wealth of Ant tasks and types, like javac, copy or jar. For this layer Gradle provides integration simply by relying on Groovy, and the fantastic AntBuilder.

Finally, since build scripts are Groovy scripts, you can always execute an Ant build as an external process. Your build script may contain statements like: "ant clean compile".execute().[1]

You can use Gradle’s Ant integration as a path for migrating your build from Ant to Gradle. For example, you could start by importing your existing Ant build. Then you could move your dependency declarations from the Ant script to your build file. Finally, you could move your tasks across to your build file, or replace them with some of Gradle’s plugins. This process can be done in parts over time, and you can have a working Gradle build during the entire process.

Using Ant tasks and types in your build

In your build script, a property called ant is provided by Gradle. This is a reference to an AntBuilder instance. This AntBuilder is used to access Ant tasks, types and properties from your build script. There is a very simple mapping from Ant’s build.xml format to Groovy, which is explained below.

You execute an Ant task by calling a method on the AntBuilder instance. You use the task name as the method name. For example, you execute the Ant echo task by calling the ant.echo() method. The attributes of the Ant task are passed as Map parameters to the method. Below is an example of the echo task. Notice that we can also mix Groovy code and the Ant task markup. This can be extremely powerful.

Example 1. Using an Ant task
GroovyKotlin
build.gradle
task hello {
    doLast {
        String greeting = 'hello from Ant'
        ant.echo(message: greeting)
    }
}
Output of gradle hello
> gradle hello

> Task :hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

You pass nested text to an Ant task by passing it as a parameter of the task method call. In this example, we pass the message for the echo task as nested text:

Example 2. Passing nested text to an Ant task
GroovyKotlin
build.gradle
task hello {
    doLast {
        ant.echo('hello from Ant')
    }
}
Output of gradle hello
> gradle hello

> Task :hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

You pass nested elements to an Ant task inside a closure. Nested elements are defined in the same way as tasks, by calling a method with the same name as the element we want to define.

Example 3. Passing nested elements to an Ant task
GroovyKotlin
build.gradle
task zip {
    doLast {
        ant.zip(destfile: 'archive.zip') {
            fileset(dir: 'src') {
                include(name: '**.xml')
                exclude(name: '**.java')
            }
        }
    }
}

You can access Ant types in the same way that you access tasks, using the name of the type as the method name. The method call returns the Ant data type, which you can then use directly in your build script. In the following example, we create an Ant path object, then iterate over the contents of it.

Example 4. Using an Ant type
GroovyKotlin
build.gradle
task list {
    doLast {
        def path = ant.path {
            fileset(dir: 'libs', includes: '*.jar')
        }
        path.list().each {
            println it
        }
    }
}

More information about AntBuilder can be found in 'Groovy in Action' 8.4 or at the Groovy Wiki.

Using custom Ant tasks in your build

To make custom tasks available in your build, you can use the taskdef (usually easier) or typedef Ant task, just as you would in a build.xml file. You can then refer to the custom Ant task as you would a built-in Ant task.

Example 5. Using a custom Ant task
GroovyKotlin
build.gradle
task check {
    doLast {
        ant.taskdef(resource: 'checkstyletask.properties') {
            classpath {
                fileset(dir: 'libs', includes: '*.jar')
            }
        }
        ant.checkstyle(config: 'checkstyle.xml') {
            fileset(dir: 'src')
        }
    }
}

You can use Gradle’s dependency management to assemble the classpath to use for the custom tasks. To do this, you need to define a custom configuration for the classpath, then add some dependencies to the configuration. This is described in more detail in Declaring Dependencies.

Example 6. Declaring the classpath for a custom Ant task
GroovyKotlin
build.gradle
configurations {
    pmd
}

dependencies {
    pmd group: 'pmd', name: 'pmd', version: '4.2.5'
}

To use the classpath configuration, use the asPath property of the custom configuration.

Example 7. Using a custom Ant task and dependency management together
GroovyKotlin
build.gradle
task check {
    doLast {
        ant.taskdef(name: 'pmd',
                    classname: 'net.sourceforge.pmd.ant.PMDTask',
                    classpath: configurations.pmd.asPath)
        ant.pmd(shortFilenames: 'true',
                failonruleviolation: 'true',
                rulesetfiles: file('pmd-rules.xml').toURI().toString()) {
            formatter(type: 'text', toConsole: 'true')
            fileset(dir: 'src')
        }
    }
}

Importing an Ant build

You can use the ant.importBuild() method to import an Ant build into your Gradle project. When you import an Ant build, each Ant target is treated as a Gradle task. This means you can manipulate and execute the Ant targets in exactly the same way as Gradle tasks.

Example 8. Importing an Ant build
GroovyKotlin
build.gradle
ant.importBuild 'build.xml'
Output of gradle hello
> gradle hello

> Task :hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

You can add a task which depends on an Ant target:

Example 9. Task that depends on Ant target
GroovyKotlin
build.gradle
ant.importBuild 'build.xml'

task intro(dependsOn: hello) {
    doLast {
        println 'Hello, from Gradle'
    }
}
Output of gradle intro
> gradle intro

> Task :hello
[ant:echo] Hello, from Ant

> Task :intro
Hello, from Gradle

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

Or, you can add behaviour to an Ant target:

Example 10. Adding behaviour to an Ant target
GroovyKotlin
build.gradle
ant.importBuild 'build.xml'

hello {
    doLast {
        println 'Hello, from Gradle'
    }
}
Output of gradle hello
> gradle hello

> Task :hello
[ant:echo] Hello, from Ant
Hello, from Gradle

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

It is also possible for an Ant target to depend on a Gradle task:

Example 11. Ant target that depends on Gradle task
GroovyKotlin
build.gradle
ant.importBuild 'build.xml'

task intro {
    doLast {
        println 'Hello, from Gradle'
    }
}
Output of gradle hello
> gradle hello

> Task :intro
Hello, from Gradle

> Task :hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

Sometimes it may be necessary to “rename” the task generated for an Ant target to avoid a naming collision with existing Gradle tasks. To do this, use the AntBuilder.importBuild(java.lang.Object, org.gradle.api.Transformer) method.

Example 12. Renaming imported Ant targets
GroovyKotlin
build.gradle
ant.importBuild('build.xml') { antTargetName ->
    'a-' + antTargetName
}
Output of gradle a-hello
> gradle a-hello

> Task :a-hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

Note that while the second argument to this method should be a Transformer, when programming in Groovy we can simply use a closure instead of an anonymous inner class (or similar) due to Groovy’s support for automatically coercing closures to single-abstract-method types.

Ant properties and references

There are several ways to set an Ant property, so that the property can be used by Ant tasks. You can set the property directly on the AntBuilder instance. The Ant properties are also available as a Map which you can change. You can also use the Ant property task. Below are some examples of how to do this.

Example 13. Setting an Ant property
GroovyKotlin
build.gradle
ant.buildDir = buildDir
ant.properties.buildDir = buildDir
ant.properties['buildDir'] = buildDir
ant.property(name: 'buildDir', location: buildDir)

Many Ant tasks set properties when they execute. There are several ways to get the value of these properties. You can get the property directly from the AntBuilder instance. The Ant properties are also available as a Map. Below are some examples.

Example 14. Getting an Ant property
GroovyKotlin
build.gradle
println ant.antProp
println ant.properties.antProp
println ant.properties['antProp']

There are several ways to set an Ant reference:

Example 15. Setting an Ant reference
GroovyKotlin
build.gradle
ant.path(id: 'classpath', location: 'libs')
ant.references.classpath = ant.path(location: 'libs')
ant.references['classpath'] = ant.path(location: 'libs')

There are several ways to get an Ant reference:

Example 16. Getting an Ant reference
GroovyKotlin
build.gradle
println ant.references.antPath
println ant.references['antPath']

Ant logging

Gradle maps Ant message priorities to Gradle log levels so that messages logged from Ant appear in the Gradle output. By default, these are mapped as follows:

Table 1. Ant message priority mapping
Ant Message Priority Gradle Log Level

VERBOSE

DEBUG

DEBUG

DEBUG

INFO

INFO

WARN

WARN

ERROR

ERROR

Fine tuning Ant logging

The default mapping of Ant message priority to Gradle log level can sometimes be problematic. For example, there is no message priority that maps directly to the LIFECYCLE log level, which is the default for Gradle. Many Ant tasks log messages at the INFO priority, which means to expose those messages from Gradle, a build would have to be run with the log level set to INFO, potentially logging much more output than is desired.

Conversely, if an Ant task logs messages at too high of a level, to suppress those messages would require the build to be run at a higher log level, such as QUIET. However, this could result in other, desirable output being suppressed.

To help with this, Gradle allows the user to fine tune the Ant logging and control the mapping of message priority to Gradle log level. This is done by setting the priority that should map to the default Gradle LIFECYCLE log level using the AntBuilder.setLifecycleLogLevel(java.lang.String) method. When this value is set, any Ant message logged at the configured priority or above will be logged at least at LIFECYCLE. Any Ant message logged below this priority will be logged at most at INFO.

For example, the following changes the mapping such that Ant INFO priority messages are exposed at the LIFECYCLE log level.

Example 17. Fine tuning Ant logging
GroovyKotlin
build.gradle
ant.lifecycleLogLevel = "INFO"

task hello {
    doLast {
        ant.echo(level: "info", message: "hello from info priority!")
    }
}
Output of gradle hello
> gradle hello

> Task :hello
[ant:echo] hello from info priority!

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

On the other hand, if the lifecycleLogLevel was set to ERROR, Ant messages logged at the WARN priority would no longer be logged at the WARN log level. They would now be logged at the INFO level and would be suppressed by default.

API

The Ant integration is provided by AntBuilder.


1. In Groovy you can execute Strings. To learn more about executing external processes with Groovy have a look in 'Groovy in Action' 9.3.2 or at the Groovy wiki