Ant vs Maven vs Gradle

28/12/2020

Choosing the Right Build Tool: Ant vs Maven vs Gradle

During software development, developers have to rebuild the same code over and over again. They often try to use bash scripts or other scripting languages to automate the task. However, there are build tools available that are more appropriate for build automation. The predominant build tools are:

Let’s investigate the tools to find out more.

Apache Ant with Ivy

Apache Ant is a Java-based command line tool that uses XML files to define build scripts. It’s predominantly used for Java builds but it can also be used for C/C++ development. Built-in tasks provide ways to compile, assemble, test and run software applications. Users can also create their own “antlibs” to enhance the functionality of Ant. Apache Ivy is a dependency management tool that integrates easily with Ant to provide a more robust ecosystem. The development of Ant started in 2000.

Pros

  • Better control over the overall build process
  • Flexible enough to work with any work process

Cons

  • XML based build files can grow large and unmaintainable
  • Lots of time and resources are necessary to maintain the build scripts
  • IDE integration is difficult to achieve

Ant with Ivy Example

You can install the latest Ant from here. You have to download the zip, expand and put the bin folder in your path. You can use the following command to see if Ant is installed properly:

$ ant -version
Apache Ant(TM) version 1.10.1 compiled on February 2 2017

Once you have Ant installed, you can download the latest Ivy jar and put it in the lib folder inside the Ant directory.

After you have Ant installed, create folders helloworld and helloworld/src. Inside the src folder, put helloworld.java file with the code:

/**************************

Prints Out "Hello World!"

***************************/
public class helloworld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

}

Now in the helloworld folder create a build.xml file with the following code:

<project xmlns:ivy="antlib:org.apache.ivy.ant" name="helloworld" default="jar">

<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="bin.dir" value="${build.dir}/bin"/>
<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="${bin.dir}"/>
<jar destfile="${bin.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/>
</target>

</project>

And in the same helloworld folder, create the ivy.xml file with the following code:

<ivy-module version="2.0">
<info organisation="org.apache" module="helloworld"/>
<dependencies>
<dependency org="junit" name="junit" rev="4.12"/>
</dependencies>
</ivy-module>

The directory structure should look like this:

helloworld
|– build.xml
|– ivy.xml
`– src
       `– helloworld.java

Now you can run the build with the command:

$ ant jar

A successful build should provide output like this:

$ ant jar
Buildfile: /Users/zak/_work/LearnBuildScripts/LearnANT/helloworld/build.xml

resolve:
[ivy:retrieve] :: Apache Ivy 2.4.0 – 20141213170938 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/Users/zak/BuildTools/ANT/apache
-ant-1.10.1/lib/ivy-2.4.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#helloworld;working@Zakirs-
MacBook-Air.local
[ivy:retrieve]     confs: [default]
[ivy:retrieve]     found junit#junit;4.12 in public
[ivy:retrieve]     found org.hamcrest#hamcrest-core;1.3 in public
[ivy:retrieve] :: resolution report :: resolve 397ms :: artifacts dl 15ms
———————————————————————
|                  |            modules            ||   artifacts   |
|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
———————————————————————
|      default     |   2   |   0   |   0   |   0   ||   4   |   0   |
———————————————————————
[ivy:retrieve] :: retrieving :: org.apache#helloworld
[ivy:retrieve]     confs: [default]
[ivy:retrieve]     0 artifacts copied, 4 already retrieved (0kB/39ms)

compile:
[mkdir] Created dir: /Users/zak/_work/LearnBuildScripts/LearnANT/helloworld/build/
classes
[javac] /Users/zak/_work/LearnBuildScripts/LearnANT/helloworld/build.xml:22: warning:
‘includeantruntime’was not set, defaulting to build.sysclasspath=last; set to false
for repeatable builds
[javac] Compiling 1 source file to /Users/zak/_work/LearnBuildScripts/LearnANT/
helloworld/build/classes

jar:
[mkdir] Created dir: /Users/zak/_work/LearnBuildScripts/LearnANT/helloworld/build/bin
[jar] Building jar: /Users/zak/_work/LearnBuildScripts/LearnANT/helloworld/build/bin/
helloworld.jar

BUILD SUCCESSFUL
Total time: 6 seconds

You can try out the jar file like this:

$ java -cp build/bin/helloworld.jar helloworld
Hello World!

We have defined the jar file to be put in the build/bin folder. The folders get created during the build. The ant jar command calls the jar target in the build.xml.

Maven

Maven was developed to resolve the problems faced with Ant-based scripting. It kept the XML files but took a different approach to organization. In Ant, developers have to create all the tasks. Maven decreases the task creation by implementing stronger standards for organizing code. As a result, it’s easier to get started on standard projects.

It also introduced dependency downloads which made the development easier. Before the introduction of Ivy in Ant, users had to manage dependencies locally. Maven adopted the dependency management philosophy first.

However, Mavens strict standards make it difficult to write custom build scripts. The tool is easy to work with as long as the project follow the strict standards.

Pros

  • Automatic dependency downloads
  • All dependencies are automatically recorded in source control as part of the Maven scripts
  • Standardizes and simplifies the build process
  • Easily integrates with IDEs and CI/CD systems

Cons

  • Not flexible in creating custom workflows
  • Steep learning curve and the process is difficult for novices to understand
  • Time-consuming to solve build problems and new library integrations
  • Not good with multiple versions of the same dependency

Maven Example

You can download the latest Maven from here. You can check the installation like this:

$ mvn –version
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d; 201710-18T00:58:13-07:00)
Maven home: /Users/zak/BuildTools/Maven/apache-maven-3.5.2
Java version: 1.8.0_74, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.6", arch: "x86_64", family: "mac"

Create a helloworld folder and generate a project with the following command:

$ mvn archetype:generate -DgroupId=com.companyname.helloworld -DartifactId=helloworld
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

It should create the folder structure and generate the output that looks like this:

[INFO] Scanning for projects…
[INFO]
[INFO] ————————————————————————
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ————————————————————————
[INFO]
[INFO] >>> maven-archetype-plugin:3.0.0:generate (default-cli) > generate-sources
@ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.0.0:generate (default-cli) < generate-sources
@ standalone-pom <<<
[INFO]
[INFO]
[INFO] — maven-archetype-plugin:3.0.0:generate (default-cli) @ standalone-pom —
[INFO] Generating project in Batch mode
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Old (1.x) Archetype:
maven-archetype-quickstart:1.0
[INFO] —————————————————————————-
[INFO] Parameter: basedir, Value: /Users/zak/_work/LearnBuildScripts/LearnMaven
[INFO] Parameter: package, Value: com.companyname.helloworld
[INFO] Parameter: groupId, Value: com.companyname.helloworld
[INFO] Parameter: artifactId, Value: helloworld
[INFO] Parameter: packageName, Value: com.companyname.helloworld
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/zak/_work/
LearnBuildScripts/LearnMaven/helloworld
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 8.602 s
[INFO] Finished at: 2018-01-27T00:05:37-08:00
[INFO] Final Memory: 15M/152M
[INFO] ————————————————————————

The folder structure should look like this:

helloworld
|— pom.xml
`— src
    |— main
    |   `java
    |       `— com
    |           `— companyname
    |               `— helloworld
    |                   `— App.java
    `test
        `java
            `— com
                `— companyname
                    `— helloworld
                        `— AppTest.java

The pom.xml contains the build configurations. Inside the pom.xml the code looks like this:

<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.companyname.helloworld</groupId>
<artifactId>helloworld</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>helloworld</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

You can generate the jar file using the following command:

$ mvn package

[INFO] Scanning for projects…
[INFO]
[INFO] ————————————————————————
[INFO] Building helloworld 1.0-SNAPSHOT
[INFO] ————————————————————————
[INFO]
[INFO] — maven-resources-plugin:2.6:resources (default-resources) @ helloworld —
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e.
build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/zak/_work/LearnBuildScripts/LearnMaven/
helloworld/src/main/resources
[INFO]
[INFO] — maven-compiler-plugin:3.1:compile (default-compile) @ helloworld —
[INFO] Changes detected – recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is
platform dependent!
[INFO] Compiling 1 source file to /Users/zak/_work/LearnBuildScripts/LearnMaven/
helloworld/target/classes
[INFO]
[INFO] — maven-resources-plugin:2.6:testResources (default-testResources) @
helloworld —
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e.
build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/zak/_work/LearnBuildScripts/LearnMaven/
helloworld/src/test/resources
[INFO]
[INFO] — maven-compiler-plugin:3.1:testCompile (default-testCompile) @ helloworld —
[INFO] Changes detected – recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is
platform dependent!
[INFO] Compiling 1 source file to /Users/zak/_work/LearnBuildScripts/LearnMaven
/helloworld/target/test-classes
[INFO]
[INFO] — maven-surefire-plugin:2.12.4:test (default-test) @ helloworld —
[INFO] Surefire report directory: /Users/zak/_work/LearnBuildScripts/LearnMaven
/helloworld/target/
surefire-reports

——————————————————-
T E S T S
——————————————————-
Running com.companyname.helloworld.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.014 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] — maven-jar-plugin:2.4:jar (default-jar) @ helloworld —
[INFO] Building jar: /Users/zak/_work/LearnBuildScripts/LearnMaven/helloworld/target/
helloworld-1.0-SNAPSHOT.jar
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 5.624 s
[INFO] Finished at: 2018-01-27T00:11:10-08:00
[INFO] Final Memory: 16M/114M
[INFO] ————————————————————————

You can run the jar file like this:

$ java -cp target/helloworld-1.0-SNAPSHOT.jar com.companyname.helloworld.App
Hello World!

The jar file is put in the target folder.

Gradle

Gradle combines the power of Ant and Maven. The first version of Gradle was released in 2012. It has seen fast adoption. Google is currently using it for Android OS.

Instead of XML, Gradle uses the Groovy language. As a result, build scripts in Gradle are easier to write and read. It was initially using Ivy for dependency management, but it is using its own dependency engine now.

Pros

  • Provides standardization while staying flexible
  • Easy to read and write build scripts
  • Better at handling multiple versions of dependencies
  • Able to handle multiple programming languages and technologies
  • Active community helping develop the tool
  • Gradle DSL (Domain-Specific Language) makes it simple configuration structure
  • Gradle provides performance improvements using incrementally, build cache and the Gradle Daemon

Cons

  • IDE integration not as good as Maven

Gradle Example

You can install Gradle from here. Once you set up Gradle in your path, you can check it by:

$ gradle –version

————————————————————
Gradle 4.5
————————————————————

Build time:   2018-01-24 17:04:52 UTC
Revision:     77d0ec90636f43669dc794ca17ef80dd65457bec

Groovy:       2.4.12
Ant:          Apache Ant(TM) version 1.9.9 compiled on February 2 2017
JVM:          1.8.0_74 (Oracle Corporation 25.74-b02)
OS:           Mac OS X 10.11.6 x86_64

Next, create the following directory structure:

helloworld
|– build.gradle
` src
    |– main
       ` java
            ` helloworld
                ` helloworld.java

For the helloworld.java put the code from the Ant example. And for build.gradle put in the following code:

apply plugin: ‘java’
 
version = ‘1.0’
 
repositories {
    mavenCentral()
}
 
dependencies {
    testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’
}

You can use “gradle tasks –all” command to look at all the commands available. Gradle automatically picks up the plugins you specify in the build.gradle file and shows you the extra tasks available due to the plugins.

You can get the build by running:

$ gradle jar

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

You can run your jar like this:

$ java -cp build/libs/helloworld-1.0.jar helloworld
Hello World!

The jar file is put in the build/libs folder.

Conclusion

Among the build tools, Ant can be useful for smaller projects while Maven is better for making sure all developers follow the same rules. Gradle is the latest tool that provides the most flexibility.

References:

ONET IDC thành lập vào năm 2012, là công ty chuyên nghiệp tại Việt Nam trong lĩnh vực cung cấp dịch vụ Hosting, VPS, máy chủ vật lý, dịch vụ Firewall Anti DDoS, SSL… Với 10 năm xây dựng và phát triển, ứng dụng nhiều công nghệ hiện đại, ONET IDC đã giúp hàng ngàn khách hàng tin tưởng lựa chọn, mang lại sự ổn định tuyệt đối cho website của khách hàng để thúc đẩy việc kinh doanh đạt được hiệu quả và thành công.
Bài viết liên quan

Install Oracle JDK 11 on Arch Linux

The full form of JDK is Java Development Kit. It is a set of tools used to compile, run, and debug Java applications. JDK...
29/12/2020

Gradle Repositories

Gradle looks for external dependencies in the repositories. A Gradle repository is organized using group, name, and version....
28/12/2020

Install OpenJDK 9 on Ubuntu

Java is a high level programming language. It is a compiled programming language. But it doesn’t compile Java code to...
28/12/2020
Bài Viết

Bài Viết Mới Cập Nhật

SỰ KHÁC BIỆT GIỮA RESIDENTIAL PROXY VÀ PROXY DATACENTER
17/02/2024

Mua Proxy v6 US Private chạy PRE, Face, Insta, Gmail
07/01/2024

Mua shadowsocks và hướng dẫn sữ dụng trên window
05/01/2024

Tại sao Proxy Socks lại được ưa chuộng hơn Proxy HTTP?
04/01/2024

Mua thuê proxy v4 nuôi zalo chất lượng cao, kinh nghiệm tránh quét tài khoản zalo
02/01/2024