Manage your Java build dependencies with Apache Ivy
Every languague, it seems, has utilities that help you automate the building process. C and C++, for example, have make and cmake, while Java developers can use Maven or Ant. Unlike Maven, Ant doesn't do project dependency solving – that's where Apache's Ivy dependency manager comes in, to help make complex builds a breeze.
Tools like make and Ant came into existence to keep developers from wasting time rebuilding the same software over and over again when only minor parts of the code were modified. Once upon a time modifying a local variable's name in one of the files in a large C project with hundreds of files would lead to the entire project being rebuilt. By contrast, make rebuilds only files that were modified directly or, based on programmers' directives, depended on the modified files. This cuts build times, especially with big projects or underpowered hardware.
Java developers wrote Ant especially for building Java applications. One of the biggest differences between make and Ant is in their file formats. While make has a format all for itself, the makefile, Ant uses XML to create rules and targets. In this context, a rule is a way to tell Ant how to build software, while a target tells Ant what to build. For example, you can have a target named "all" that builds the binaries and the documentation, and another named "bin" that builds only the binaries. The name of the XML file must be build.xml.
Here's a simple build.xml file from Java Forums that defines four targets:
<project name="Hello" default="compile">
<target name="clean" description="remove intermediate files">
<target name="clobber" depends="clean" description="remove all artifact files">
<target name="compile" description="compile the Java source code to class files">
<javac srcdir="." destdir="classes"/>
<target name="jar" depends="compile" description="create a Jar file for the application">
<fileset dir="classes" includes="**/*.class"/>
<attribute name="Main-Class" value="HelloProgram"/>
One of the advantages of using XML for build files is that they are more readable than makefiles. A badly written makefile can be tedious to read and understand.
Getting and using Ant and Ivy
You can install Ant on Centos 6.x, x86 or x86_64, with the command
yum install ant. For Ivy, the folks over at JPackage, which offers Java-related repositories for RPM and APT-based Linux systems, have Ivy available, and it's also available from the official repos of Fedora 17 – but let's see how easy Ivy makes things, even starting with its installation process. Once you have Ant installed, create an empty directory, and in it create a build.xml file that duplicates the build example in the Ivy documentation:
The code in this file defines a target that takes care of downloading Ivy, then another that installs it, compiles the necessary libraries (notice that this target – aptly named "go" – has a dependency, clearly defined up front), creates a class named "Hello," capitalizes the message properly, then cleans up after itself and exits.
To run it, type
ant in the folder that contains the file, and watch it as it takes care of the dependencies, including Ivy:
[echo] We are now ready to execute our simple program with its dependency on commons-lang.
[echo] Let's go!
[java] standard message : hello ivy !
[java] capitalized by org.apache.commons.lang.WordUtils : Hello Ivy !
Total time: 14 seconds
This example speaks more about the simplicity and power of Ivy than hundreds of manuals. Speaking of manuals, the documentation is, as usual with Apache projects, stellar. It's unlikely you'll need any info that isn't available on the site.
Ivy can handles transitive dependencies, which is another way of saying nested dependencies. For example, my project depends on JUnit, but JUnit itself depends on other jars, and so on. With Ivy, I only need to tell it about the JUnit dependency (first-order dependencies) and it will take care of the rest, recursively. To define dependencies with Ivy, you need an ivy.xml file, and its contents should be of the form:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="./config/ivy/ivy-doc.xsl"?>
<info organisation="com" module="integratebutton" />
<dependency name="junit" rev="4.10" />
You can define as many dependencies as you want, as long as you're sure they're first-order dependencies.
If you're worried about the correct versions being pulled down as dependencies, don't. Ivy "knows" what version of the dependency is, say, compatible with JUnit 4.10, and will get that for you. This doesn't mean that, in more complex development environments, you no longer need a version control system. Think about it this way: Eventually you will need to revisit code written a long time ago, and without a proper repository it will be hard to find the exact revision where you introduced a particular feature.
Every developer wants an easy-to-use tool that can generate dependency reports on the fly, especially when working on larger projects. Ivy can do this for you, with the
report Ant task:
<target name="ivy-report" depends="init-ivy">
The more you'll be using Ivy, the more you'll enjoy its simplicity, and the ability to be powerful and helpful despite that. Built with programmer efficiency in mind, and coupled with Ant, it's a tool that every Java developer should know about.
This work is licensed under a Creative Commons Attribution 3.0 Unported License