Ant vs Gradle vs Maven

Java Build Tools

There is a good deal of build automation tools available for Java development. But the most common ones are Ant, Maven and Gradle. Though Ant is the oldest, nowadays Maven and Gradle are the two heavy hitters. With Gradle being the newest kid on the block. So which tool is best suited for fresh development projects? Let’s take a deep dive in all three build systems first.

Ant

Ant was the first among all these three build systems. It was first released in 2000 by the apache foundation. Ant is the acronym for “Another neat tool”.

Ant had a very low learning curve thus allowing anyone to start using in just about no time. The result is that it became the most popular build tool of its time.

Ant uses XML build.xml files to create build scripts. It was soon apparent that there is a need for dependency management. So Ant adopted Apache Ivy as the dependency management tool.

The power of Ant comes from the fact that it does not force any structure or pattern to the code base or the dependencies. This gives the developers immense control over the build process. But it also means that developers are required to write all the commands that can lead to the successful execution of any given task.

code example

<project
    xmlns:ivy="antlib:org.apache.ivy.ant">
    
    <available classname="org.apache.ivy.Main" property="ivy.installed"/> 
    
    <target name="install-ivy">
        <mkdir dir="${user.home}/.ant/lib"/>
        <get dest="${user.home}/.ant/lib/ivy.jar" src="https://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
        <fail message="Ivy has been installed. Run the build again"/>
    </target>
    
    <!-- clean: delete all built classes -->
    <target name="clean">
        <delete dir="target" />
    </target>
    
    <target name="resolve" depends="install-ivy">
        <ivy:cachepath pathid="compile.path">
            <dependency org="org.hibernate" name="hibernate" rev="3.2.7.ga" conf="default">
                <exclude org="javax.transaction"/>
            </dependency>
        </ivy:cachepath>
    </target>
 
    <!-- build: build all the classes  -->
    <target name="build" depends="clean, resolve">
        <mkdir dir="target" />
        <mkdir dir="target/classes"/>
        <javac srcdir="src" destdir="target/classes" classpathref="compile.path"/>
    </target>
 
    <target name="package" depends="build">
        <jar destfile="../HelloWorld.jar" basedir="target/classes">
            <manifest>
                <attribute name="Main-Class"
                  value="antExample.HelloWorld" />
            </manifest>
        </jar>
    </target>
 
    <target name="run" depends="package">
        <java jar="target/HelloWorld.jar" fork="true" />
    </target>
</project>

We can execute the build and packaging the Jar file by triggering command:

ant package

When we trigger this command, it will execute the “clean” task first and delete the target directory. Once the clean phase completes the “build” phase will get triggered which will compile the classes and re-create the target structure.

Last will be the “package” phase which will package the classes into a jar file and place it in the target directory. This addition of all the steps of the build process in the build.xml results in huge build.xml file. As the project grows this file becomes unmanageable.

Maven

‘Jason van Zyl’ first released Maven in 2004 to improve upon the problems that developers faced when using the Ant build tool. Maven uses XML files, specifically pom.xml to control the build process and dependency management. Though it differs dramatically from Ant’s build.xml.

Maven is a life-cycle based build system. Where each life-cycle has crystal clear goals. The life-cycle is linear that makes the Maven build process easiest of them all to understand. As long as the project’s structure follows the standards and the project adhere to the life-cycle it can pass the complete build process with ease.

Many available plugins manage the goals and life-cycle of the Maven build system. Java language is used to create these plugins. Maven defines Life-cycle goals like build, compile, package, etc which are used to fine-tune the build process. It also supports multi-module builds that can run in parallel to speed up the entire process. Maven builds the modules in topological order and keeps the build process parallel where it can be.

Maven dependency system downloads dependencies (libraries or plugins) from repositories and put them in your local machine. These downloaded repositories then act as the cache for the subsequent builds. Maven does support both public and private repositories to download dependencies from.

However, dependency management of the Maven build tool does not handle conflicts between two or more versions of the same library very well. Which leads to unexpected results or build failures (Something ivy is much better at). The other point to consider is the structure of pom.xml which is very strict and highly standardized which results in a very simple process of creating a new pom.xml file but at the cost of flexibility.

This loss of flexibility makes the customization of the build process a nightmare for the developers.

code example

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.apoorvparmar</groupId>
    <artifactId>HelloWorld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
            </dependency>
    </dependencies>
</project>

The above pom.xml suffices to make sure that the build of the HelloWorld program will succeed with dependency resolved at the build time. However, now the project must follow the structure required by the Maven build system otherwise Maven won’t be able to build the project.

+---src
| +---main
| | +---java
| | | ---com
| | | ---apoorvparmar
| | | HelloWorld.java

We can trigger the jar build using the command:

mvn package

This will trigger the package life-cycle goal of the Maven build system. The order of execution will be the “compile” life-cycle goal and then the “package” goal cause package goal depends on compile life-cycle goal. Once the process is complete, all the classes and the packaged jar file will be available in the target directory.

Gradle

Gradle is the newest build system among the three. It is built around the concepts of Apache Maven and Apache Ant build systems. You can say it has a bit of good from both the worlds. It was first released in 2007 and later in 2013 with the latest released version being 6.3 released on 24th March 2020.

Unlike Ant and Maven, Gradle uses Groovy to define the build process and dependency management. Cause Groovy is a scripting language based on JVM, the build scripts for Gradle are much cleaner and smaller. Gradle is also the default build tool adopted by Google for the build systems for Android project.

Like Maven, Gradle is also designed to handle multi-module builds. Just like Maven, it can also run module builds in parallel. Gradle can go one step ahead and can execute multiple tasks in parallel. It also supports incremental additions in the build process as it keeps track of all the parts that changed from the last build.

Gradle builds by building a graph of the task dependencies. These tasks are then executed to perform the required steps to complete the task. These tasks can run in parallel and only the tasks that need to be completed are triggered. In other words, cause Gradle keeps track of what changed it knows which tasks should be performed. This results in the fastest build time between all the three build systems.

code example

apply plugin:'java'

repositories {
    mavenCentral()
}


jar {
    baseName = 'HelloWorld'
    version = '0.0.1-SNAPSHOT'
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.10'
}

We can trigger complete build using following command:

gradle build

Above command will trigger a build process where it’ll compile only the “modified java” files. Once compilation of these files is complete, Gradle will package the classes into a nice little Jar file which we can execute.

Which tool to choose?

Now we know, what are these three build systems and we got to see a brief introduction on how we can use and work with them. We also see all the build tools have their respective strengths and weaknesses. Let’s try to figure out which one is the best pick for you.

Ant

For any newcomer, Ant is the clearest tool of all. Just by reading the build.xml, they can understand what it does and how it does it. However, writing Ant tasks and configuring build.xml can easily get very complex and become unmanageable even for a seasoned developer. This also means starting a new project with an Ant build tool requires a lot of knowledge and patience.

Maven

Maven can simplify that process a great deal. It also allows customization of the metadata and provides a good dependency management tool. But for huge projects, the pom.xml can easily become bloated. But usually, developers divide all these huge projects into multiple modules and we can split pom.xml across modules which can result in neat and small pom.xml(s).

Maven does support simple yet very effective dependency management system and cause it follows a standard, it’s easy to work things out. But for complex build systems and if we want to add complexities, modifying maven build process can become a nightmare.

We can still modify the build process using maven plugins with relative ease and there is a huge list of them available. But if you still need some functionality that is not directly available then there is no other option but add a new plugin of your own.

Gradle

Just like Maven, Gradle also uses the same structure for the codebase but it does not restrict developers. It can just work with any code structure. Just change the structure as per your liking and instruct Gradle to work with it. Also like Maven, Gradle provides a good list of plugins to customize the build process but the number of plugins on the Maven platform far exceeds the number of plugins available on Gradle.

Cause Gradle is a script based build system, it gives a lot of flexibility to the developers and customizing the builds are very easy. But cause Gradle is the newest of ’em all the number of developers who have worked extensively on the Gradle is much lower than the that on Maven.

Endgame

In the end, What you choose in between Ant, Maven and Gradle will depend primarily on what you need.

If you are building a project that needs complete control on the build system and you cannot use any available plugins on Maven or Gradle system then Ant is the way to go. But nowadays a very few projects need that much flexibility and what we require is a little cleanness and simplicity.

Gradle is more powerful and flexible. Gradle can also yield much cleaner and simpler build scripts. However, there are times when you don’t need that power or flexibility and simplicity is all that you need that maven can provide.

Leave a Reply

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