Managing dependent jar files
When a project's build depends on jar files from other projects, whether
internal, external, or both, your build process needs to incorporate them.
The tidiest way to manage the classpath for compiling in an Ant file is to
build a reference to a classpath. A classpath reference can be created with
a <path> block outside of any particular target, probably after the build
property files have been read in:
<property file="build.properties"/>
<property file="default.properties"/>
<path id="classpath">
<pathelement location="${servlet.jar}"/>
<pathelement location="${xerces.jar}"/>
<pathelement location="${mail.jar}"/>
<pathelement location="${activation.jar}"/>
</path>
The classpath referenced is then used in the compilation target as follows:
<target name="compile" depends="init">
<javac srcdir="${src.dir}"
destdir="${build.dir}"
debug="${debug}"
optimize="${optimize}"
deprecation="${deprecation}">
<classpath refid="classpath"/>
<include name="**/*.java" />
</javac>
</target>
You've probably noticed that the path block which builds the classpath breaks
the model we've created so far by being project dependent - the jar files used
to compile this project are specifically named. Actually we're using properties
which define specifically what directory each jar file is found in, but the
point remains. Many Jakarta projects such as Tomcat use this convention, which
isn't unreasonable given that their build process is much too complex to be
generic - the Tomcat build files are very specific to Tomcat, so they can't
simply be plugged into a different project. Nevertheless, let's continue to
focus on making a build file which can be dropped into any fairly normal Java
project.
One tactic used to handle the classpath is to have a directory which contains
all of the jar files needed by the project, then write the path block to include
everything in that directory.
<path id="classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
This isn't a bad idea if you maintain a lib directory which contains all of
the jar files for the project, perhaps checked into CVS, perhaps on a file
server. But some organizations have extended this concept to have a shared
directory which contains every jar file which might conceivably be needed
on any project, and reading them all into the classpath. Not only can this
slow things down, it is messy since you no longer have a clear idea of what
files a given project depends on. Upgrading a jar file to a newer version
may break some projects, so everything gets brittle.
A better idea is to adapt the build.properties file idea to have a file which
contains the names of the jar files needed by a project.
<path id="classpath">
<fileset dir="${lib.dir}">
<includesfile name="dep.list"/>
</fileset>
</path>
This assumes that all of the jar files are found in ${lib.dir}. If there are
multiple locations, multiple FileSets can be used:
<path id="classpath">
<fileset dir="${project.lib}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${common.lib}">
<includesfile name="dep.list"/>
</fileset>
</path>
This example assumes a project lib directory which contains jars specific to
this project, and a common lib directory from which jars named in the dep.list
file will be included in the classpath.
Further innovations on this concept use a network server with a collection of
jar files, and utilize Ant tasks for HTTP or FTP to retrieve the updated jar
files, as an alternative to checking jar files into CVS.
Keeping cruft out of CVS
One of the goals of our build system is to keep the code repository free from
cruft, that is, files which tend to appear in a developer's copy of the project
but will only clutter up the repository if checked in. The canonical examples
of these are IDE configuration files, editor backups (e.g. emacs foo.java~),
and the developer specific build.properties file we're using here. Allowing these
to get checked into CVS not only clutters up the repository with cruft, it can
also cause conflicts as developers override each others' IDE preferences.
A larger example of cruft is the output files of the build process, in
particular .class files, jars, and Javadoc HTML files. Since these can all be
generated by each developer, and change whenever source code itself changes,
having them in CVS is redundant, slowing down updates and other CVS operations.
Many projects resolve this by keeping the output directory outside the project
directory entirely. For example, if the project is checked out into a directory
called /homes/me/src/ourProject, the build, inluding .class files, jar file,
and Javadoc output, might go into /homes/me/ourProjectBuild.
But this doesn't resolve the issue of IDE configuration files and the like.
The solution is to include a file in your project repository called .cvsignore,
which lists files and subdirectories which should not be included in CVS
operations. The Tomcat project's .cvsignore file has three lines:
build
build.properties
dist
This allows the build and dist directories to be created in the same directory
the CVS code is checked out into, and also keeps build.properties out of the
repository. You can add typical IDE configuration files to this. Basically,
when you run cvs update, look at which files CVS complains about not being
in the repository, and which don't need to be in the repository, and add them
to .cvsignore.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.