Java Build Tools Comparisons: Ant vs Maven vs Gradle

In the beginning, there was Make as the only build tool available. Later on, it was improved with GNU Make. However, since then our needs increased and, as a result, build tools evolved. The whole JVM ecosystem is dominated by three build tools:

  1. Apache Ant with Ivy
  2. Maven
  3. Gradle

Ant with Ivy

Pros
  • First among modern build tools, Similar to Make.
  • Easy to learn, that's why it became popular very soon.
  • Through Ant, you can have complete control over the build process.
  • Ant has the ability to include plugins.
  • Each element of work (a target in Ant’s lingo) can be combined and reused
Cons
  • Based on procedural programming paradigm.
  • Ant uses XML as the format.
  • Ant XML files speedily become unmanageably big even for small projects.
  • Ant does not have the predefined set of build cycles, we need to write the scripts for everything.
  • Ant is simply a Build tool, It doesn’t have dependency management system.
Later on, as dependency management over the network became a must, Ant adopted Apache Ivy.Later on, as dependency management over the network became a must, Ant adopted Apache Ivy.


Maven

Maven was released in 2004. Its goal was to improve upon some of the problems developers were facing when using Ant.

Pros
  • Maven comes with pre-defined targets for performing certain well-defined tasks such as compilation of code and its packaging.
  • Maven introduced the ability to download dependencies over the network (later on adopted by Ant through Ivy).
  • The main benefit from Maven is its life-cycle, As long as the project is based on certain standards, with Maven one can pass through the whole life cycle with relative ease.
Cons
  • Maven also uses XML as the format but follows different structure than Ant.
  • Dependencies management does not handle well conflicts between different versions of the same library (something Ivy is much better at).
  • Customization of targets (goals) is hard, Its harder to write custom build scripts in Maven then Ant.
  • Maven configuration is written in XML continuous being big and cumbersome.
In the mean time the interest for DSLs (Domain Specific Languages) continued increasing. The idea is to have languages designed to solve problems belonging to a specific domain. In case of builds, one of the results of applying DSL is Gradle.In the mean time the interest for DSLs (Domain Specific Languages) continued increasing. The idea is to have languages designed to solve problems belonging to a specific domain. In case of builds, one of the results of applying DSL is Gradle.


Gradle

Gradle combines good parts of both tools and builds on top of them with DSL and other improvements. It has Ant’s power and flexibility with Maven’s life-cycle and ease of use. Initially, Gradle used Apache Ivy for its dependency management. Later own it moved to its own native dependency resolution engine. The end result is a tool that was released in 2012 and gained a lot of attention in a short period of time, e.g. Google adopted Gradle as the default build tool for the Android OS.
Pros
  • Instead of XML, Gradle has its own DSL based on Groovy (one of JVM languages)
  • Build scripts are shorter and clearer than Ant or Maven.
Cons
  • Gradle doesn’t have the concept of parent projects that can provide inheritable version numbers.
This image explains all things in very brief

Comparisons through Code examples

We’ll create build scripts in all 3 frameworks that will compile, perform static analysis, run unit tests and, finally, create JAR files, And then we’ll compare the syntax. By comparing the code for each task we’ll be able to get a better understanding of the differences and make an informed decision regarding the choice of the build tool.

Ant with Ivy

Ivy dependencies need to be specified in the ivy.xml file.

[ivy.xml]
<ivy-module version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info organisation="org.apache" module="java-build-tools" />

    <dependencies>
        <dependency org="junit" name="junit" rev="4.11"></dependency>
    </dependencies>
</ivy-module>

Task of this build.xml is to compile the source code and generate a JAR file.

[build.xml]
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar">
    <property name="src.dir" value="src" />
    <property name="build.dir" value="build" />
    <property name="classes.dir" value="${build.dir}/classes" />
    <property name="jar.dir" value="${build.dir}/jar" />
    <property name="lib.dir" value="lib" />
    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
    </path>

    <target name="resolve">
        <ivy:retrieve />
    </target>

    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <target name="compile" depends="resolve">
        <mkdir dir="${classes.dir}" />
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id" />
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}" />
        <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}" />
    </target>
</project>

To run the Ant task that creates the JAR file you need to execute following.

ant jar

Maven


[pom.xml]
<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 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.programming.mitra</groupId>
    <artifactId>java-build-tools</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

To run the Maven goal that creates the JAR file, execute following.

mvn package

The major difference is that with Maven we don’t need to specify what should be done. We’re not creating tasks but setting the parameters (what are the dependencies, what plugins to use…). This shows the major difference between Ant and Maven. Later promotes the usage of conventions and provides goals (targets) out-of-the-box. Both Ant and Maven XML files tend to grow big with time. To illustrate that, we’ll add Maven CheckStyle, FindBugs and PMD plugins that will take care of static analysis. All three are fairly standard tools used, in one form or another, in many Java projects. We want all static analysis to be executed as part of a single target verify together with unit tests. Moreover, we should specify the path to the customs check style configuration and make sure that it fails on error. Additional Maven code is following:

[pom.xml]
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.12.1</version>
    <executions>
        <execution>
            <configuration>
                <configLocation>config/checkstyle/checkstyle.xml</configLocation>
                <consoleOutput>true</consoleOutput>
                <failsOnError>true</failsOnError>
            </configuration>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>2.5.4</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.1</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

To run the Maven goal that runs both unit tests and static analysis with CheckStyle, FindBugs, and PMD execute following.
mvn verify
We had to write a lot of XML that does some very basic and commonly used set of tasks. On real projects with a lot more dependencies and tasks, Maven pom.xml files can easily reach hundreds or even thousands of lines of XML.

Gradle

[build.gradle]
apply plugin:'java'
apply plugin:'checkstyle'
apply plugin:'findbugs'
apply plugin:'pmd'

version ='1.0'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group:'junit', name:'junit', version:'4.11'
}

Not only that the Gradle code is much shorter and, to those familiar with Gradle, easier to understand than Maven, but it actually introduces many useful tasks not covered with the Maven code we just wrote. To get the list of all tasks that Gradle can run with the current configuration, please execute the following.

gradle tasks --all

Gradle has a lot of tasks already available out-of-the-box or through plugins. For example, by seeing the following line it is probably not clear to those not initiated into mysteries of Gradle what tasks will be unlocked for us to use.

Simple apply plugin:'java' code more than 20 tasks waiting for us to use.
Next Post Newer Post Previous Post Older Post Home

3 comments :

  1. Gradle - con is wrong, check gradle subproject

    ReplyDelete
    Replies
    1. Hello Liyu can you provide me some specific links

      Delete
  2. This comment has been removed by a blog administrator.

    ReplyDelete