As your Java projects get larger, they quickly become more difficult to manage. While many project management strategies exist, the default tool for Java projects is Apache Ant. Here are the basics.
Consider a Java project with 3 class files. When it’s time to compile them, the command is simply:
REM Compile all .java source files into .class files javac class1.java class2.java class3.java
You could run the main() method of one of these classes (say Class1), or bundle them in a Java ARchive (JAR) file and run it with:
REM Create the Java archive out of compiled .class files REM and specify Class1's main() as the entry point for REM the jar file. jar cfe MyProject.jar Class1 class1.class class2.class class3.class REM Run the jar file java -jar MyProject.jar
As the number of classes in your project grows however, retyping these commands become cumbersome. One solution would be to store them as a script file (Unix bsh, ksh, Windows batch, perl, python, etc.) and run that file every time you make a change to the code. The catch is, a change to just one class file recompiles the entire project, which could take several minutes (or more). What we need is a system that can detect which class files have changed, recompile only those, and then rebuild the archive. Enter Ant.
Tracing its lineage back to the well-known utility make, Apache’s Ant allows you to define your project in a separate XML file. You then run the ant utility which reads this file, determines the minimal set of build actions required, and executes them. It supports a rich set of tasks that help you build different target types, perform various documentation tasks, and even allow you to download 3rd party libraries from the Internet as part of the build process.
We’ve already see that most of these functions are performed by the Eclipse IDE, and will shortly learn about more modern tools like maven and gradle that can as well. For many simple projects however, Ant is a perfectly reasonable choice for these services.
Again, we’re assuming your development environment is Windows 8.1; the installation process is similar for other Windows and Unix-like environments and the operation is identical.
First, point your browser to the Ant binary distributions page, and download the .zip archive of the latest stable version (1.9.4 at the time of this writing). Store it in a reasonable location, say c:\Ant, and extract it there. The package should end up in C:\Ant\apache-ant-1.9.4.
There are some environment variables to set up. To review, these are parameters maintained by the Operating System that can be used by any application running. Click-right on the start icon, then select System / Advanced System Settings / Environment Variables…. Variables are divided into those for the current user and those for the system; work with user-specific variables here.
First, create a New… variable called ANT_HOME with the value of Ant’s location, C:\Ant\apache-ant-1.9.4 in this case. Next, Edit… the PATH variable to include the location of the Ant binaries, C:\Ant\apache-ant-1.9.4\bin, or %ANT_HOME%\bin for short. Programs in your PATH do not need their full path specified when executed. Multiple locations in your PATH variable are separated by semicolons (;).
Finally, ensure that a similar configuration exists for your Java Development Kit (JDK); the JAVA_HOME variable points to the JDK home and %JAVA_HOME%\bin is in your path.
Test your installation by opening up a command prompt (cmd) and running:
java -version javac -version ant -v
The version of each tool should be printed.
By default, ant looks for a file named ‘build.xml’ when it runs. This file describes the layout and locations of your project files, the ‘targets’ to create, and the ‘tasks’ needed to create them. The basic structure of the file is:
<project> <target name="target1"> <task1 /> </target> <target name="target2" depends="target1"> <task2 /> </target> <target name="target3" depends="target2"> <task3 /> </target> </project>
Here we have defined 3 targets, each with their own tasks needed to create them. We also see that there are dependencies between the targets; target3 depends on target2, which in turn depends on target 1. Other dependency relationships are possible, as well as other elements and properties in the build.xml file, but let’s illustrate those with an example.
Consider a trivial Java project with two class files. The first, AntProject.java, contains only the main() entry point of the application and DateUtils.java contains a method that returns the current date and is called by AntProject.
Now consider the build.xml file that governs the build process for these classes.
Seems like a lot for such a small application, but there’s a lot going on here. When going through these files, it helps to have the Ant Documentation handy for reference.
First notice that there are 4 targets defined: compile, dist, run, and clean. As their names suggest, these represent the typical stages of the development process. Specific targets are executed at the command line, for example:
or, because the <project /> element identifies the default target as ‘run’, running ant with no arguments executes that target. Also note the dependencies listed. for example if you wanted to execute the ‘dist’ target, ant would check if the ‘compile’ target needs to be executed first. Also note that <property /> elements are available and can be used like program variables, parameterizing various aspects of the build.
While the names of the targets are arbitrary, the tasks are strictly defined in the ant documentation. For example, the <javac /> task specifies the source of the .java files, compiling every file it sees in that location, and deposits the .class files in the indicated destination. This behavior can be modified with <javac /> excludes and excludesfile properties. <javac />, however, is smart enough to know which .class files are stale by comparing their dates with the corresponding .java files, and compiling only those that are out of date. Try it!
The <jar /> task in the “dist” target creates the Java archive, along with the manifest file that describes the “Main-Class” whose main() method is called when the jar is executed. Again, all files in the basedir directory are included in the archive, unless specifically excluded.
Managing External Dependencies
Let’s say you’re not satisfied with the performance of the DateUtils.getDate() method. Instead of using the stock java.util.Date class, you decide to use the third-party library Joda-Time. It’s compatible with java.util.Date and has better support for different time zones and more precise system clocks.
Typically you would download the library, include it in your project, update the classpath, and deploy it with the rest of your class files. Fortunately, most of this can be automated within ant builds using Apache Ivy.
To use Ivy, you’ll need to do the following:
- Extract the jar from the latest Ivy package, and install it in %USERPROFILE%\.ant\lib. You could also create an ant target to do this with the <mkdir /> and <get /> tasks if you’re particularly ambitious.
- Create an ivy.xml file that describes the external libraries to import. In our case:
- Create a new target in your build.xml file to download the required libraries and resolve any dependencies. Once you add the xmlns:ivy=”antlib:org.apache.ivy.ant” namespace to your <project />, you can achive this with the <ivy:retrieve /> task.
- Add additional targets to create the necessary classpath property for your manifest and add the necessary jar’s to your Java archive.
For more details on this process, here’s a good example of how it works.
Ivy can also be used within the Eclipse IDE, instead of the command-line ant utility. To start, run Eclipse, go to Help / Eclipse Marketplace…, and install IvyDE. We’ll revisit IvyDE in a future post.
Ant is a powerful project management tool, with a long history in the Java community. Today, most enterprise-class applications, including Proloquor.net, have moved to maven because of it’s ability to manage many different project types. We’ll cover both maven and gradle shortly.
A great site for quickly learning Java technologies like Ant, without getting too bogged down into the theory, is Yong Mook Kim’s Mkyong.com, from which much of the above material is derived.