10. Ant vs Maven vs Gradle
● General
● Dependency Management
● Build Life Cycle
● Dealing with Non-Java
Editor's Notes
Project Object Model (POM)
The goal you indicate in the command line is linked to the lifecycle of Maven. For example, the build lifecycle (you also have the clean and site lifecycles which are different) is composed of the following phases:
validate: validate the project is correct and all necessary information is available.
compile: compile the source code of the project.
test: test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed.
package: take the compiled code and package it in its distributable format, such as a JAR.
integration-test: process and deploy the package if necessary into an environment where integration tests can be run.
verify: run any checks to verify the package is valid and meets quality criteria
install: install the package into the local repository, for use as a dependency in other projects locally.
deploy: done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.
Compile - This is the default scope when no other scope is provided. Dependencies with this scope are available on the classpath of the project in all build tasks. They are also propagated to the dependent projects. They are also transitive
Provided - We use this scope to mark dependencies that should be provided at runtime by JDK or a container. A good use case for this scope would be a web application deployed in some container, where the container already provides some libraries itself. For example, this could be a web server that already provides the Servlet API at runtime. The provided dependencies are available only at compile time and in the test classpath of the project. These dependencies are also not transitive.
Runtime - The dependencies with this scope are required at runtime. But we don't need them for the compilation of the project code. Because of that, dependencies marked with the runtime scope will be present in the runtime and test classpath, but they will be missing from the compile classpath. A JDBC driver is a good example of dependencies that should use the runtime scope:
Test - We use this scope to indicate that dependency isn't required at standard runtime of the application but is used only for test purposes.Test dependencies aren't transitive and are only present for test and execution classpaths. The standard use case for this scope is adding a test library such as JUnit to our application:
System - System scope is very similar to the provided scope. The main difference is that system requires us to directly point to a specific jar on the system.It's worthwhile to mention that system scope is deprecated.
Import - It's only available for the dependency type pom. import indicates that this dependency should be replaced with all effective dependencies declared in its POM.
Ant: Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extensions points dependent upon each other (http://ant.apache.org/manual).
Maven: Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information (https://maven.apache.org/).
Gradle: Gradle is an open-source build automation tool focused on flexibility and performance. Gradle build scripts are written using a Groovy or Kotlin DSL (https://docs.gradle.org/current/userguide/userguide.html).
2.1 General
· Ant - No conventions and everything is procedural, at least when you declare it that way. You can do whatever you want and, in any order, because Ant is a toolbox.
· Maven - Conventions that you are stuck to because Maven is a framework. Syntax is also limited to declarative.
· Gradle - Conventions from which you can easily deviate, and also the ability to be both procedural and declarative.
2.2 Dependency Management
· Ant - None built in, and requires you to use Ivy (http://ant.apache.org/ivy/). Downloading dependencies to use as part of your Ant build also requires some strange looking boilerplate code, so that you define Ant task definitions after having the jar files available.
· Maven - Built in but difficult to customize (http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
· Gradle - Built in and easy to customize (http://www.gradle.org/docs/current/userguide/dependency_management.html)
2.3 Build Life Cycle
· Ant - Made up of targets, which can depend on or call other targets. There is no enforced life cycle, which can lead to chaotic builds.
· Maven - Made up of 3 life cycles, which are made of phases, which are made up of goals. There are 30 phases used to cover the clean, default, and site life cycles. (http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
· Gadle - Made up of three distinct phases: Initialization, Configuration, and Execution. This is significantly simpler than the 30 phases of maven. (http://www.gradle.org/docs/current/userguide/build_lifecycle.html)
2.4 Dealing with non-Java
Ant - With easy access to the command-line and the ability to do whatever you want, non-Java support is only limited by your imagination. Dealing with programmatic problems in a declarative language leads to complexity, for example when doing modular Flex, a mostly dead language (https://stackoverflow.blog/2017/08/01/flash-dead-technologies-might-next/), builds (http://jvalentino.blogspot.com/2010/03/flex-ant-build-optimized-modules_24.html)
· Maven - If you want to deal with non-Java you are going to need to write a custom plugin. When I used to work with Flex it was much easier to build an Ant macro and put it in a jar versus building a Maven plugin.
· Gradle - It is possible to do the same things you did with Ant, or deal with and possibly write your own Gradle plugin.