Ant, Maven and Gadle – A side by Side Comparison
A little over a year ago we were staring a new project for a client as part of a new project we had options for using a build system Ant, Maven, or Gradle were choices given that we had some time before the project started I put together a project to compare the three build systems. Up to that time the client had used Maven and neither us or the client had any particular experience using Gradle.
The project was setup so that the thee systems would build the same project and would be configured to do the same set of tasks. I picked out a tutorialthat used the same framework that we were going to be using on the client project. Just the first chapter of the tutorial was implemented in the project as that would be enough to gather the data needed to make an informed decision. The tasks that the build system need to do were as follows.
- Build a deploy-able war file.
- Run unit tests against the project.
- Deploy the war file to a local application container
- Clean up all the build and deployment artifacts including the expanded application folder for the deployed application.
What follows is my findings at that time.
AntWe ended up in the end going with Maven, but I am planning on converting one of my side projects to use Gradle in the near future. It should also be noted that since I wrote this maven has come out with version 3 which has several speed improvements along the lines of what Gradle does. I was going to update the number but I can’t find the original project, I think it would be interesting to do this again and see what difference a year makes. But that’s for another time.
Ant is certainly not the oldest build management system, that title probably goes to make, but it has been the standard build system for java projects since 2000 giving it ample time to mature. Ant is a configuration heavy system, you have to explicitly define all of it actions, called targets; Ant is only as intelligent as you configure it to be. Out of all the systems that were investigated this was the only one that ended up having 3 different files associated with it, the standard build.xml, build.properties, and ivy.xml (ivy will be discussed later). Being that there is not a standard way for things to be setup this particular build was the one that took the longest to setup even though most of the targets were already defined in the tutorial. It also ended up having the most lines of configuration of the bunch and the most explicitly defined targets.The targets with (*) would be main targets that would be used on a daily basis.
- download-ivy – download the ivy jar
- install-ivy – install ivy into the ant class path
- usage (default) – displays usage info (not updated)
- build – build the java file
- buildwar – compile a war file.
- deploy (*) – deploy the war to the application container
- clean (*) – clean the build artifacts and application container
- buildtests – build the tests.
- test (*) – runs the tests.
Dependency Management with Ivy
One of the things that Ant lacks out of the box that the other two systems have is dependency management. Apache has addressed this with a project called Ivy. Ivy uses the standard maven repositories to resolve dependencies and build class paths which are defined within an ivy.xml file. Getting the dependencies to work correctly with Ivy was the single largest time sink due to a weird configuration attribute that is not explained well in the ivy documentation. In general the ivy documentation is poor at best.
It never was figured out how to only retrieve the junit jar for tests and leave it out of the deployed war and not to include compiled tests classes. So at this point the demo still has the junit jar and tests classes being deployed with the rest of the application which should be considered a defect in that particular build file.
IDE Integration
Ant was around before eclipse and as such eclipse allows you to create a new project based on an ant target. Doing so was painless. There were a couple of hitches though, first the unit test was not imported into the project. Second is that the Ivy dependencies are not a part of that ant integration that eclipse has implemented. Apache does have an eclipse plug-in that will read that ivy.xml file and pull the dependencies into the project. Setting that plug-in up was fairly painless as it creates an ant library and you just have to make sure that it is in your class path configuration. There was one dependency that was not pulled into the project which was the application container servlet api jars which are copied from the application container home in the build file. This was fairly simply fixed by crating a library and adding the lib directory from the application container to that library.
Maven
Maven2 has been around since 2005. It takes a different approach from ant, rather than relying on the implementer configuring everything, maven favors convention. For example if you have your source files in a folder named src/main/java maven will automatically find the sources, no configuration necessary. Everything in maven has a default setup so as long as your project follows these conventions there is no more setup needed. While Maven does state that everything can be changed to how you want it the configuration options are defied by the plug-ins which can be hard to break out of in practice. Maven does have the ability to call to ant targets so if there is missing functionality it can be added using ant and called within the maven life cycle.
The size of the maven .pom file, which is the configuration file that maven uses based on xml, ended up in the mid range of the three projects. The time to implement was the least, but this can be attributed to the current familiarity of Maven. Its dependency management is built right into the tool, and this dependency management has been so successful its the model that most other dependency management systems in the java world are based off of. Currently it is hard to find a java build systems that doesn’t use the maven repositories and is not able to use the repository to resolve any transitive dependencies. The one hitch in the dependency management was that unlike Ant I wasn’t able to use the local application container libraries. It would have been possible to install them in the local repository but that would need everyone using the project to also do this. Maven has a dependency scope which denotes that the dependency shouldn’t be included in any artifacts that are created so the build uses a library in the repository but that library is provided in the deployment environment. Using this scope another general servlet library was use for compilation but it would have been preferred to use the application container ones to avoid any possible conflicts.
Rather than targets Maven defines plug-ins and there are three main plug-ins that would be used on a daily basis. The ones that would be of use to anyone building the demo are.
IDE Integration
- package – build and deploy the war to the resin container.
- clean – cleanup all build artifacts including the resin container war file copy and expanded folder.
- test – run the test suite
Eclipse doesn’t have native support for maven projects, but maven has an eclipse plug-in that generates an eclipse project which can be imported as an existing project. This works well and there were no problems doing this. The command to run this plug-in is “mvn eclipse:eclipse”. (Note: There is also an eclipse plugin called m2e which helps with maven integration into eclipse. )
Gradle
Gradle is certainly one of the newest build systems having version 1 released at the end of February 2011. Gradle rather than having a configuration based on xml like Ant and Maven is written in Groovya scripting language on the JVM. This gives us a pure programming language to develop our build on. Using Groovy Gradle can use any existing ant targets, Maven plug-ins or any Java classes making it a very powerful tool. It also uses the standard maven conventions so as long as everything is laid out like a maven project it can find everything without issue.
Dependencies are handled using the maven repositories. Groups of dependencies can be defined, Gradle plug-ins have predetermined dependency groups that you can add the dependencies to which indicate how/where the dependencies are to be used much like maven’s dependency scope. Unlike Maven you can include files on the file system easily which allowed the libraries in the application container’s lib folder to be used to compile with.
By far the number of lines to get the build to work was much less than the other two, the time to implement the build system was between ant and maven, this can be attributed to the unfamiliarity with this particular system. Of note is the unit test output is very nice and a vast improvement over the default maven surefire plug in output. Although it should also be noted that the unit tests don’t output a result on the command line, at least when all the tests pass, so that had to be added. The build tasks that are of interest for this project are
The tasks with (#) are ones that are explicitly defined within the build configuration, the rest are supplied by plug-ins. On average it took Gradle longer to start the build process but Gradle does seem to keep track of changes per task so if there are no changes since the last time you ran the localDeploy task Gradle will as it runs through the plug-in tree for the build tell you that there have been no changes for each task it goes through and skip running that plug-in. This sort of short cutting could save a lot of time over Maven and Ant.
- build – build the war file.
- test – run the unit tests
- localDeploy (#)- builds and deploys the war to the local resin container.
- clean – clean the build artifacts
- localClean (#)- clean the build artifacts and the resin container.
IDE Integration
Much like Maven there is an eclipse plug-in available for Gradle that creates an eclipse project. The only issue was that it crated a link to a folder that it already had defined so that there was a conflict removing the link fixed the issue. Otherwise it was just as good as the Maven integration.
Side By Side Comparison
Conclusions
Ant Maven GradleNumber of Files 3 1 1Total Lines 138 73 38approx Setup Time 6-8 hrs 1-2 hrs 3-4 hrsIDE Integration Eclipse Native, dependency management with plug-in Maven Native Gradle NativeTime to Deploy From clean (dependencies Cached) 8 seconds 13 Seconds 10.671 SecondsTime To Clean 0 seconds 4 Seconds 2.249 SecondsPros -Most Mature-Quickest Build Time-Totally Configurable -Largest Current Brain Share, most experience in the company-Very quick for standard items due to conventions.-A lot of plug-ins available for different tasks -Build configuration is in Groovy for total control-Change detection will only run tasks that have changed since last run. -Smallest configuration, arguably the most readable-Has the benefit of hindsight and improves on the mistakes made by both Ant and Maven Cons -No native dependency management-Longest Setup time-Even with the long setup things still were not working as expected-Longest build time-Can be hard to break out of a convention if needed. -Newest tech, not as much available information. -Configuration file format not as intuitive (not xml)-Biggest chance to shoot self in the foot.
While all are practical solutions from working with these three system I would tend to lean towards using Gradle while the format is a bit unfamiliar and the conventions used in the configuration file can be tricky to figure out first. It is hard to deny the power of being able to define custom tasks using a pure scripting language and its ability to leverage the other two build systems. This seems to result in much more compact and understandable build configurations.
Maven while being the second potential choice which is what the current Holiday Inn application uses (and in cases abuses) has the current brain trust, any project where there might be non standard things going on might have problems molding a maven driven build into what it needs to be.