Chapter 1. Getting Started: Compiling, Running, and Debugging

Introduction

This chapter covers some entry-level tasks that you need to know how to do before you can go on—it is said you must crawl before you can walk, and walk before you can ride a bicycle. Before you can try out anything in this book, you need to be able to compile and run your Java code, so I start there, showing several ways: the JDK way, the Integrated Development Environment (IDE) way, and the build tools (Ant, Maven, etc.) way. Another issue people run into is setting CLASSPATH correctly, so that’s dealt with next. Deprecation warnings follow after that, because you’re likely to encounter them in maintaining “old” Java code. The chapter ends with some general information about conditional compilation, unit testing, assertions, and debugging.

If you don’t already have Java installed, you’ll need to download it. Be aware that there are several different downloads. The JRE (Java Runtime Environment) is a smaller download for end users. The JDK or Java SDK download is the full development environment, which you’ll want if you’re going to be developing Java software.

Standard downloads for the current release of Java are available at Oracle’s website.

You can sometimes find prerelease builds of the next major Java version on http://java.net. For example, while this book’s third edition was being written, Java 8 was not yet released, but JDK 8 builds could be obtained from the OpenJDK project. The entire (almost) JDK is maintained as an open source project, and the OpenJDK source tree is used (with changes and additions) to build the commercial and supported Oracle JDKs.

If you’re already happy with your IDE, you may wish to skip some or all of this material. It’s here to ensure that everybody can compile and debug their programs before we move on.

Compiling and Running Java: JDK

Problem

You need to compile and run your Java program.

Solution

This is one of the few areas where your computer’s operating system impinges on Java’s portability, so let’s get it out of the way first.

JDK

Using the command-line Java Development Kit (JDK) may be the best way to keep up with the very latest improvements in Java. Assuming you have the standard JDK installed in the standard location and/or have set its location in your PATH, you should be able to run the command-line JDK tools. Use the commands javac to compile and java to run your program (and, on Windows only, javaw to run a program without a console window). For example:

C:\javasrc>javac HelloWorld.java

C:\javasrc>java HelloWorld
Hello, World

C:\javasrc>

As you can see from the compiler’s (lack of) output, this compiler works on the Unix “no news is good news” philosophy: if a program was able to do what you asked it to, it shouldn’t bother nattering at you to say that it did so. Many people use this compiler or one of its clones.

There is an optional setting called CLASSPATH, discussed in Using CLASSPATH Effectively, that controls where Java looks for classes. CLASSPATH, if set, is used by both javac and java. In older versions of Java, you had to set your CLASSPATH to include “.”, even to run a simple program from the current directory; this is no longer true on current Java implementations.

Sun/Oracle’s javac compiler is the official reference implementation. There were several alternative open source command-line compilers, including Jikes and Kaffe but they are, for the most part, no longer actively maintained.

There have also been some Java runtime clones, including Apache Harmony, Japhar, the IBM Jikes Runtime (from the same site as Jikes), and even JNODE, a complete, standalone operating system written in Java, but since the Sun/Oracle JVM has been open-sourced (GPL), most of these projects have become unmaintained. Harmony was retired by Apache in November 2011, although parts of it are still in use (e.g., parts of Harmony’s JavaSE runtime library are used in the popular Android mobile operating system).

Mac OS X

The JDK is pure command line. At the other end of the spectrum in terms of keyboard-versus-visual, we have the Apple Macintosh. Books have been written about how great the Mac user interface is, and I won’t step into that debate. Mac OS X (Release 10.x of Mac OS) is built upon a BSD Unix (and “Mach”) base. As such, it has a regular command line (the Terminal application, hidden away under /Applications/Utilities), as well as all the traditional Mac tools. Java SE 6 was provided by Apple and available through Software Update. Effective with Java 7, Apple has devolved this support to Oracle to make the distributions, which are now available for download (avoid the JRE-only downloads). More information on Oracle Java for OS X is available.

Mac OS X users can use the command-line JDK tools as above or Ant (see Automating Compilation with Apache Ant). Compiled classes can be packaged into “clickable applications” using the Jar Packager discussed in Running a Program from a JAR. Alternatively, Mac fans can use one of the many full IDE tools discussed in Compiling, Running, and Testing with an IDE.

Editing and Compiling with a Syntax-Highlighting Editor

Problem

You are tired of command-line tools, but not ready for an IDE.

Solution

Use a syntax-highlighting editor.

Discussion

It’s less than an IDE (see the next recipe), but more than a command line. What is it? It’s an editor with Java support. Tools such as TextPad, Visual SlickEdit, and others are free or low-cost windowed editors (many primarily for Microsoft Windows) that have some amount of Java recognition built in, and the ability to compile from within the editor. TextPad recognizes quite a number of file types, including batch files and shell scripts, C, C++, Java, JSP, JavaScript, and many others. For each of these, it uses syntax highlighting to denote keywords, comments, string literals, etc., usually by using one color for keywords, another for class variables, another for locals, etc. This is very useful in spotting when part of your code has been swallowed up by an unterminated /* comment or a missing quote.

Though this isn’t the same as the deep understanding of Java that a full IDE might possess, experience has shown that it definitely aids programmer productivity. TextPad also has a “compile Java” command and a “run external program” command. Both of these have the advantage of capturing the entire command output into a window, which may be easier to scroll than a command-line window on some platforms. On the other hand, you don’t see the command results until the program terminates, which can be most uncomfortable if your GUI application throws an exception before it puts up its main window. Despite this minor drawback, TextPad is a very useful tool. Other editors that include color highlighting include vim (an enhanced version of the Unix tool vi, available for Windows and Unix platforms from http://www.vim.org), the ever-popular Emacs editor, and more.

And speaking of Emacs, because it is so extensible, it’s natural that people have built enhanced Java capabilities for it. One example is Java Development Environment for Emacs (JDEE), an Emacs “major mode” (jde-mode, based on c-mode) with a set of menu items such as Generate Getters/Setters. You could say that JDEE is in between using a Color-Highlighting Editor and an IDE.

Even without JDEE, Emacs features dabbrev-expand, which does class and method name completion. It is, however, based on what’s in your current edit buffers, so it doesn’t know about classes in the standard API or in external JARs. For that level of functionality, you have to turn to a full-blown IDE, such as those discussed in Compiling, Running, and Testing with an IDE.

Compiling, Running, and Testing with an IDE

Problem

It is cumbersome to use several tools for the various development tasks.

Solution

Use an integrated development environment (IDE), which combines editing, testing, compiling, running, debugging, and package management.

Discussion

Many programmers find that using a handful of separate tools—a text editor, a compiler, and a runner program, not to mention a debugger (see Debugging with JDB)—is too many. An IDE integrates all of these into a single toolset with a graphical user interface. Many IDEs are available, ranging all the way up to fully integrated tools with their own compilers and virtual machines. Class browsers and other features of IDEs round out the ease-of-use feature sets of these tools. It has been argued many times whether an IDE really makes you more productive or if you just have more fun doing the same thing. However, today most developers use an IDE because of the productivity gains. Although I started as a command-line junkie, I do find that the following IDE benefits make me more productive:

Code completion
Ian’s Rule here is that I never type more than three characters of any name that is known to the IDE; let the computer do the typing!
“Incremental compiling” features
Note and report compilation errors as you type, instead of waiting until you are finished typing.
Refactoring
The ability to make far-reaching yet behavior-preserving changes to a code base without having to manually edit dozens of individual files.

Beyond that, I don’t plan to debate the IDE versus the command-line process; I use both modes at different times and on different projects. I’m just going to show a few examples of using a couple of the Java-based IDEs.

The three most popular Java IDEs, which run on all mainstream platforms and quite a few niche ones, are Eclipse, NetBeans, and IntelliJ IDEA. Eclipse is the most widely used, but the others each have a special place in the hearts and minds of some developers. If you develop for Android, the ADT has traditionally been developed for Eclipse, but it is in the process of moving to IntelliJ as the basis for “Android Studio,” which is in early access as this book goes to press.

Let’s look first at NetBeans. Originally created by NetBeans.com and called Forte, this IDE was so good that Sun bought the company, and Oracle now distributes NetBeans as a free, open source tool for Java developers. There is a plug-in API; and quite a few plug-ins available. You can download the free version and extension modules. If you want support for it, the Oracle “Java Development Tools Support” offering covers NetBeans, Oracle JDeveloper, and Oracle Enterprise Pack for Eclipse—see the “Pro Support.” For convenience to those getting started with Java, you can download a single bundle that includes both the JDK and NetBeans, from the Oracle download site.

NetBeans comes with a variety of templates. In Figure 1-1, I have opted for the plain Java template.

NetBeans: New Class Wizard
Figure 1-1. NetBeans: New Class Wizard

In Figure 1-2, NetBeans lets me specify a project name and package name for the new program I am building, and optionally to create a new class, by giving its full class name.

NetBeans: Name that class
Figure 1-2. NetBeans: Name that class

In Figure 1-3, we have the opportunity to type in the main class.

NetBeans: Entering main class code
Figure 1-3. NetBeans: Entering main class code

In Figure 1-4, we run the main class.

NetBeans: Running the application
Figure 1-4. NetBeans: Running the application

Perhaps the most popular cross-platform, open source IDE for Java is Eclipse, originally from IBM and now shepherded by the Eclipse Foundation, now the home of many software projects. Just as NetBeans is the basis of Sun Studio, so Eclipse is the basis of IBM’s Rational Application Developer (RAD). All IDEs do basically the same thing for you when getting started; see, for example, the Eclipse New Java Class Wizard shown in Figure 1-5. It also features a number of refactoring capabilities, shown in Figure 1-6.

Eclipse: New Java Class Wizard
Figure 1-5. Eclipse: New Java Class Wizard
Eclipse: Refactoring
Figure 1-6. Eclipse: Refactoring

The third IDE is IntelliJ IDEA. This also has a free version (open source) and a commercial version. IntelliJ supports a wide range of languages via optional plug-ins (I have installed Android and Haskell plug-ins on the system used in these screenshots). You can start by defining a new project, as shown in Figure 1-7.

IntelliJ New Project Wizard
Figure 1-7. IntelliJ New Project Wizard

To create a new class, right-click the source folder and select New→Class. Pick a name and package for your class, as shown in Figure 1-8.

IntelliJ New Class Wizard
Figure 1-8. IntelliJ New Class Wizard

You will start with a blank class. Type some code into it, such as the canonical “Hello World” app, as shown in Figure 1-9.

IntelliJ class typed in
Figure 1-9. IntelliJ class typed in

Finally, you can click the green Run button, or context-click in the source window and select Run, and have your program executed. As you can see in Figure 1-10, the output will appear in a console window, as in the other IDEs.

Mac OS X includes Apple’s Developer Tools. The main IDE is Xcode. Unfortunately, current versions of Xcode do not really support Java development, so there is little to recommend it for our purposes; it is primarily for those building non-portable (iOS-only or OS X–only) applications in the Objective-C programming language. So even if you are on OS X, to do Java development you should use one of the three Java IDEs.

How do you choose an IDE? Given that all three major IDEs (Eclipse, NetBeans, IntelliJ) can be downloaded free, why not try them all and see which one best fits the kind of development you do? Regardless of what platform you use to develop Java, if you have a Java runtime, you should have plenty of IDEs from which to choose.

IntelliJ program output
Figure 1-10. IntelliJ program output

See Also

Each IDE’s site maintains an up-to-date list of resources, including books.

All major IDEs are extensible; see their documentation for a list of the many, many plug-ins available. Most of them now allow you to find and install plug-ins from within the IDE, though they vary in how convenient they make this process. As a last resort, if you need/want to write a plug-in that extends the functionality of your IDE, you can do that too, in Java.

Using CLASSPATH Effectively

Problem

You need to keep your class files in a common directory, or you’re wrestling with CLASSPATH.

Solution

Set CLASSPATH to the list of directories and/or JAR files that contain the classes you want.

Discussion

CLASSPATH is one of the more “interesting” aspects of using Java. You can store your class files in any of a number of directories, JAR files, or ZIP files. Just like the PATH your system uses for finding programs, the CLASSPATH is used by the Java runtime to find classes. Even when you type something as simple as java HelloWorld, the Java interpreter looks in each of the places named in your CLASSPATH until it finds a match. Let’s work through an example.

The CLASSPATH can be set as an environment variable on systems that support this (Microsoft Windows and Unix, including Mac OS X). You set it the same way you set other environment variables, such as your PATH environment variable.

Alternatively, you can specify the CLASSPATH for a given command on the command line:

C:\> java -classpath c:\ian\classes MyProg

Suppose your CLASSPATH were set to C:\classes;. on Windows or ~/classes:. on Unix (on the Mac, you can set the CLASSPATH with JBindery). Suppose you had just compiled a file named HelloWorld.java into HelloWorld.class and tried to run it. On Unix, if you run one of the kernel tracing tools (trace, strace, truss, ktrace), you would probably see the Java program open (or stat, or access) the following files:

  • Some file(s) in the JDK directory
  • Then ~/classes/HelloWorld.class, which it probably wouldn’t find
  • Finally, ./HelloWorld.class, which it would find, open, and read into memory

The vague “some file(s) in the JDK directory” is release-dependent. You should not mess with the JDK files, but if you’re curious, you can find them in the System Properties under sun.boot.class.path (see Getting Information from System Properties for System Properties information).

Suppose you had also installed the JAR file containing the supporting classes for programs from this book, darwinsys-api.jar (the actual filename if you download it may have a version number as part of the filename). You might then set your CLASSPATH to C:\classes;C:\classes\darwinsys-api.jar;. on Windows or ~/classes:~/classes/darwinsys-api.jar:. on Unix. Notice that you do need to list the JAR file explicitly. Unlike a single class file, placing a JAR file into a directory listed in your CLASSPATH does not suffice to make it available.

Note that certain specialized programs (such as a web server running a Java EE Servlet container) may not use either bootpath or CLASSPATH as shown; these application servers typically provide their own ClassLoader (see Constructing a Class from Scratch with a ClassLoader for information on class loaders). EE Web containers, for example, set your web app classpath to include the directory WEB-INF/classes and all the JAR files found under WEB-INF/lib.

How can you easily generate class files into a directory in your CLASSPATH? The javac command has a -d dir option, which specifies where the compiler output should go. For example, using -d to put the HelloWorld class file into my $HOME/classes directory, I just type the following (note that from here on I will be using the package name in addition to the class name, like a good kid):

javac -d $HOME/classes HelloWorld.java
java -cp $HOME/classes starting.HelloWorld
Hello, world!

As long as this directory remains in my CLASSPATH, I can access the class file regardless of my current directory. That’s one of the key benefits of using CLASSPATH.

Managing CLASSPATH can be tricky, particularly when you alternate among several JVMs (as I do) or when you have multiple directories in which to look for JAR files. Some Linux distributions have an “alternatives” mechanism for managing this. Otherwise you may want to use some sort of batch file or shell script to control this. The following is part of the shell script that I have used—it was written for the standard shell on Unix (should work on Bash, Ksh, etc.), but similar scripts could be written in other shells or as a DOS batch file:

# These guys must be present in my classpath...
export CLASSPATH=/home/ian/classes/darwinsys-api.jar:

# Now a for loop, testing for .jar/.zip or [ -d ... ]
OPT_JARS="$HOME/classes $HOME/classes/*.jar
    ${JAVAHOME}/jre/lib/ext/*.jar
    /usr/local/jars/antlr-3.2.0"

for thing in $OPT_JARS
do
    if [ -f $thing ]; then       //must be either a file...
        CLASSPATH="$CLASSPATH:$thing"
    else if [ -d $thing ]; then       //or a directory
        CLASSPATH="$CLASSPATH:$thing"
    fi
done
CLASSPATH="$CLASSPATH:."

This builds a minimum CLASSPATH out of darwinsys-api.jar, then goes through a list of other files and directories to check that each is present on this system (I use this script on several machines on a network), and ends up adding a dot (.) to the end of the CLASSPATH.

Warning

Note that, on Unix, a shell script executed normally can change environment variables like CLASSPATH only for itself; the “parent” shell (the one running commands in your terminal or window) is not affected. Changes that are meant to be permanent need to be stored in your startup files (.profile, .bashrc, or whatever you normally use).

Downloading and Using the Code Examples

Problem

You want to try out my example code and/or use my utility classes.

Solution

Download the latest archive of the book source files, unpack it, and run Maven (see Automating Dependencies, Compilation, Testing, and Deployment with Apache Maven) to compile the files.

Discussion

The source code used as examples in this book is drawn from several source code repositories that have been in continuous development since 1995. These are listed in Table 1-1.

Table 1-1. The main source repositories
Repository nameGithub.com URLPackage descriptionApprox. size

javasrc

http://github.com/IanDarwin/javasrc

Java classes from all APIs

1,200 classes

darwinsys-api

http://github.com/Iandarwin/darwinsys-api

A published API

250 classes

A small number of examples are drawn from the older javasrcee (Java EE) examples, which I split off from javasrc due to the overall size; this is also on GitHub.

You can download these repositories from the GitHub URLs shown in Table 1-1. GitHub allows you to download, by use of git clone, a ZIP file of the entire repository’s current state, or to view individual files on the web interface. Downloading with git clone instead of as an archive is preferred because you can then update at any time with a simple git pull command. And with the amount of updating this has undergone for Java 8, you are sure to find changes after the book is published.

If you are not familiar with Git, see CVS, Subversion, Git, Oh My!.

javasrc

This is the largest repo, and consists primarily of code written to show a particular feature or API. The files are organized into subdirectories by topic, many of which correspond more or less to book chapters—for example, a directory for strings examples (Chapter 3), regex for regular expressions (Chapter 4), numbers (Chapter 5), and so on. The archive also contains the index by name and index by chapter files from the download site, so you can easily find the files you need.

There are about 80 subdirectories in javasrc (under src/main/java), too many to list here. They are listed in the file src/main/java/index-of-directories.txt.

darwinsys-api

I have built up a collection of useful stuff, partly by moving some reusable classes from javasrc into my own API, which I use in my own Java projects. I use example code from it in this book, and I import classes from it into many of the other examples. So, if you’re going to be downloading and compiling the examples individually, you should first download the file darwinsys-api-1.x.jar (for the latest value of x) and include it in your CLASSPATH. Note that if you are going to build the javasrc code with Eclipse or Maven, you can skip this download because the top-level Maven script starts off by including the JAR file for this API.

This is the only one of the repos that appears in Maven Central; find it by searching for darwinsys. The current Maven artifact is:

<dependency>
   <groupId>com.darwinsys</groupId>
   <artifactId>darwinsys-api</artifactId>
   <version>1.0.3</version>
</dependency>

This API consists of about two dozen com.darwinsys packages, listed in Table 1-2. You will notice that the structure vaguely parallels the standard Java API; this is intentional. These packages now include more than 200 classes and interfaces. Most of them have javadoc documentation that can be viewed with the source download.

Table 1-2. The com.darwinsys packages
Package namePackage description

com.darwinsys.ant

A demonstration Ant task

com.darwinsys.csv

Classes for comma-separated values files

com.darwinsys.database

Classes for dealing with databases in a general way

com.darwinsys.diff

Comparison utilities

com.darwinsys.genericui

Generic GUI stuff

com.darwinsys.geo

Classes relating to country codes, provinces/states, and so on

com.darwinsys.graphics

Graphics

com.darwinsys.html

Classes (only one so far) for dealing with HTML

com.darwinsys.io

Classes for input and output operations, using Java’s underlying I/O classes

com.darwinsys.jsptags

Java EE JSP tags

com.darwinsys.lang

Classes for dealing with standard features of Java

com.darwinsys.locks

Pessimistic locking API

com.darwinsys.mail

Classes for dealing with email, mainly a convenience class for sending mail

com.darwinsys.model

Modeling

com.darwinsys.net

Networking

com.darwinsys.preso

Presentations

com.darwinsys.reflection

Reflection

com.darwinsys.regex

Regular expression stuff: an REDemo program, a Grep variant, and so on

com.darwinsys.security

Security

com.darwinsys.servlet

Servlet API helpers

com.darwinsys.sql

Classes for dealing with SQL databases

com.darwinsys.swingui

Classes for helping construct and use Swing GUIs

com.darwinsys.swingui.layout

A few interesting LayoutManager implementations

com.darwinsys.testdata

Test data generators

com.darwinsys.testing

Testing tools

com.darwinsys.unix

Unix helpers

com.darwinsys.util

A few miscellaneous utility classes

com.darwinsys.xml

XML utilities

Many of these classes are used as examples in this book; just look for files whose first line begins:

package com.darwinsys;

You’ll also find that many of the other examples have imports from the com.darwinsys packages.

General notes

If you are short on time, the majority of the examples are in javasrc, so cloning or downloading that repo will get you most of the code from the book. Also, its Maven script refers to a copy of the darwinsys-api that is in Maven Central, so you could get 90% of the code with one git clone, for javasrc. Your best bet is to use git clone to download a copy of all three, and do git pull every few months to get updates.

Alternatively, you can download a single intersection set of all three that is made up almost exclusively of files actually used in the book, from this book’s catalog page. This archive is made from the sources that are dynamically included into the book at formatting time, so it should reflect exactly the examples you see in the book. But it will not include as many examples as the three individual archives.

You can find links to all of these from my own website for this book; just follow the Downloads link.

The three separate repositories are each self-contained projects with support for building both with Eclipse (Compiling, Running, and Testing with an IDE) and with Maven (Automating Dependencies, Compilation, Testing, and Deployment with Apache Maven). Note that Maven will automatically fetch a vast array of prerequisite libraries when first invoked on a given project, so be sure you’re online on a high-speed Internet link. However, Maven will ensure that all prerequisites are installed before building. If you choose to build pieces individually, look in the file pom.xml for the list of dependencies. Unfortunately, I will probably not be able to help you if you are not using either Eclipse or Maven with the control files included in the download.

If you have Java 7 instead of the current Java 8, a few files will not compile. You can make up “exclusion elements” for the files that are known not to compile.

All my code in the three projects is released under the least-restrictive credit-only license, the two-clause BSD license. If you find it useful, incorporate it into your own software. There is no need to write to ask me for permission; just use it, with credit.

Tip

Most of the command-line examples refer to source files, assuming you are in src/main/java, and runnable classes, assuming you are in (or have added to your classpath) the build directory (e.g., for Maven this is target/classes, and for Eclipse it is build). This will not be mentioned with each example, because it would waste a lot of paper.

Caveat Lector

The repos have been in development since 1995. This means that you will find some code that is not up to date, or that no longer reflects best practices. This is not surprising: any body of code will grow old if any part of it is not actively maintained. (Thus, at this point, I invoke Culture Club’s, “Do You Really Want to Hurt Me?”: “Give me time to realize my crimes.”) Where advice in the book disagrees with some code you found in the repo, keep this in mind. One of the practices of Extreme Programming is Continuous Refactoring—the ability to improve any part of the code base at any time. Don’t be surprised if the code in the online source directory differs from what appears in the book; it is a rare week that I don’t make some improvement to the code, and the results are committed and pushed quite often. So if there are differences between what’s printed in the book and what you get from GitHub, be glad, not sad, for you’ll have received the benefit of hindsight. Also, people can contribute easily on GitHub via “pull request”; that’s what makes it interesting. If you find a bug or an improvement, do send me a pull request!

The consolidated archive on oreilly.com will not be updated as frequently.

Automating Compilation with Apache Ant

Problem

You get tired of typing javac and java commands.

Solution

Use the Ant program to direct your compilations.

Discussion

Ant is a pure Java solution for automating the build process. Ant is free software; it is available in source form or ready-to-run from the Apache Foundation’s Ant website. Like make, Ant uses a file or files—Ant’s are written in XML—listing what to do and, if necessary, how to do it. These rules are intended to be platform-independent, though you can of course write platform-specific recipes if necessary.

To use Ant, you must create a file specifying various options. This file should be called build.xml; if you call it anything else, you’ll have to give a special command-line argument every time you run Ant. Example 1-1 shows the build script used to build the files in the starting directory. See Chapter 20 for a discussion of the syntax of XML. For now, note that the <!-- begins an XML comment, which extends to the -->.

Example 1-1. Ant example file (build.xml)
<project name="Java Cookbook Examples" default="compile" basedir=".">

  <!-- Set global properties for this build -->
  <property name="src" value="."/>
  <property name="build" value="build"/>
  <!-- Specify the compiler to use. -->
  <property name="build.compiler" value="modern"/>

  <target name="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <!-- Create the build directory structure used by compile -->
    <mkdir dir="${build}"/>
  </target>

  <!-- Specify what to compile. This builds everything -->
  <target name="compile" depends="init">

    <!-- Compile the java code from ${src} into ${build} -->
    <javac srcdir="${src}" destdir="${build}"
          classpath="../darwinsys-api.jar"/>
  </target>

</project>

When you run Ant, it produces a reasonable amount of notification as it goes:

$ ant compile
Buildfile: build.xml
Project base dir set to: /home/ian/javasrc/starting
Executing Target: init
Executing Target: compile
Compiling 19 source files to /home/ian/javasrc/starting/build
Performing a Modern Compile
Copying 22 support files to /home/ian/javasrc/starting/build
Completed in 8 seconds
$

See Also

The following sidebar and Ant: The Definitive Guide by Steve Holzner (O’Reilly).

Automating Dependencies, Compilation, Testing, and Deployment with Apache Maven

Problem

You tried Ant and liked it, but want a tool that does more automatically.

Solution

Use Maven.

Discussion

Maven is a tool one level up from Ant. Although Ant is good for managing compilation, Maven includes a sophisticated, distributed dependency management system that also gives it rules for building application packages such as JAR, WAR, and EAR files and deploying them to an array of different targets. Whereas Ant build files focus on the how, Maven files focus on the what, specifying what you want done.

Maven is controlled by a file called pom.xml (for Project Object Model). A sample pom.xml might look like this:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>my-se-project</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>my-se-project</name>
  <url>http://com.example/</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

This specifies a project called “my-se-project” (my standard-edition project) that will be packaged into a JAR file; it depends on the JUnit 4.x framework for unit testing (see Avoiding the Need for Debuggers with Unit Testing), but only needs it for compiling and running tests. If I type mvn install in the directory with this POM, Maven will ensure that it has a copy of the given version of JUnit (and anything that JUnit depends on), then compile everything (setting CLASSPATH and other options for the compiler), run any and all unit tests, and if they all pass, generate a JAR file for the program; it will then install it in my personal Maven repo (under ~/.m2/repository) so that other Maven projects can depend on my new project JAR file. Note that I haven’t had to tell Maven where the source files live, nor how to compile them—this is all handled by sensible defaults, based on a well-defined project structure. The program source is expected to be found in src/main/java, and the tests in src/test/java; if it’s a web application, the web root is expected to be in src/main/webapp by default. Of course, you can override these.

Note that even the preceding config file does not have to be, and was not, written by hand; Maven’s “archteype generation rules” let it build the starting version of any of several hundred types of projects. Here is how the file was created:

$ mvn archetype:generate \
        -DarchetypeGroupId=org.apache.maven.archetypes \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DgroupId=com.example -DartifactId=my-se-project

\[INFO] Scanning for projects...
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/
    maven-deploy-plugin/2.5/maven-deploy-plugin-2.5.pom
\[several dozen or hundred lines of downloading POM files and Jar files...]
\[INFO] Generating project in Interactive mode
\[INFO] Archetype [org.apache.maven.archetypes:maven-archetype-quickstart:1.1]
    found in catalog remote
\[INFO] Using property: groupId = com.example
\[INFO] Using property: artifactId = my-se-project
Define value for property 'version':  1.0-SNAPSHOT: :
\[INFO] Using property: package = com.example
Confirm properties configuration:
groupId: com.example
artifactId: my-se-project
version: 1.0-SNAPSHOT
package: com.example
 Y: : y
\[INFO] ------------------------------------------------------------------------
\[INFO] Using following parameters for creating project from Old (1.x) Archetype:
    maven-archetype-quickstart:1.1
\[INFO] ------------------------------------------------------------------------
\[INFO] Parameter: groupId, Value: com.example
\[INFO] Parameter: packageName, Value: com.example
\[INFO] Parameter: package, Value: com.example
\[INFO] Parameter: artifactId, Value: my-se-project
\[INFO] Parameter: basedir, Value: /private/tmp
\[INFO] Parameter: version, Value: 1.0-SNAPSHOT
\[INFO] project created from Old (1.x) Archetype in dir: /private/tmp/
    my-se-project
\[INFO] ------------------------------------------------------------------------
\[INFO] BUILD SUCCESS
\[INFO] ------------------------------------------------------------------------
\[INFO] Total time: 6:38.051s
\[INFO] Finished at: Sun Jan 06 19:19:18 EST 2013
\[INFO] Final Memory: 7M/81M
\[INFO] ------------------------------------------------------------------------

The IDEs (see Compiling, Running, and Testing with an IDE) have support for Maven. For example, if you use Eclipse, M2Eclipse (m2e) is an Eclipse plug-in that will build your Eclipse project dependencies from your POM file; this plug-in ships by default with current (Kepler) Java Developer builds of Eclipse, is tested with previous (Juno) releases, and is also available for some older releases; see the Eclipse website for plug-in details.

A POM file can redefine any of the standard “goals.” Common Maven goals (predefined by default to do something sensible) include:

clean
Removes all generated artifacts
compile
Compiles all source files
test
Compiles and runs all unit tests
package
Builds the package
install
Installs the pom.xml and package into your local Maven repository for use by your other projects
deploy
Tries to install the package (e.g., on an application server)

Most of the steps implicitly invoke the previous ones—e.g., package will compile any missing .class files, and run the tests if that hasn’t already been done in this run.

Typically there are application-server–specific targets provided; as a single example, with the JBoss Application Server “WildFly” (formerly known as JBoss AS), you would install some additional plug-in(s) as per their documentation, and then deploy to the app server using:

mvn jboss-as:deploy

instead of the regular deploy.

Maven pros and cons

Maven can handle complex projects and is very configurable. I built the darwinsys-api and javasrc projects with Maven and let it handle finding dependencies, making the download of the project source code smaller (actually, moving the download overhead to the servers of the projects themselves). The only real downsides to Maven is that it takes a bit longer to get fully up to speed with it, and the fact that it can be a bit hard to diagnose when things go wrong. A good web search engine is your friend when things fail.

One issue I fear is that a hacker could gain access to a project’s site and modify, or install a new version of, a POM. Maven automatically fetches updated POM versions. Although the same issue could affect you if you manage your dependencies manually, it is more likely that the problem would be detected before you manually fetched the infected version. I am not aware of this having happened, but it still worries me.

See Also

Start at http://maven.apache.org.

Automating Dependencies, Compilation, Testing, and Deployment with Gradle

Problem

You want a build tool that doesn’t make you use a lot of XML in your configuration file.

Solution

Use Gradle’s simple build file with “strong, yet flexible conventions.”

Discussion

Gradle is the latest in the succession of build tools (make, ant, and Maven). Gradle bills itself as “the enterprise automation tool,” and has integration with the other build tools and IDEs.

Unlike the other Java-based tools, Gradle doesn’t use XML as its scripting language, but rather a domain-specific language (DSL) based on the JVM-based and Java-based scripting language Groovy.

You can install Gradle by downloading from the Gradle website, unpacking the ZIP, and adding its bin subdirectory to your path.

Then you can begin to use Gradle. Assuming you use the “standard” source directory (src/main/java, src/main/test) that is shared by Maven and Gradle among other tools, the example build.gradle file in Example 1-2 will build your app and run your unit tests.

Example 1-2. Example build.gradle file
# Simple Gradle Build for the Java-based DataVis project
apply plugin: 'java'
# Set up mappings for Eclipse project too
apply plugin: 'eclipse'

# The version of Java to use
sourceCompatibility = 1.7
# The version of my project
version = '1.0.3'
# Configure JAR file packaging
jar {
    manifest {
        attributes 'Main-class': 'com.somedomainnamehere.data.DataVis',
                'Implementation-Version': version
    }
}

# optional feature: like -Dtesting=true but only when running tests ("test task")
test {
    systemProperties 'testing': 'true'
}

You can bootstrap the industry’s vast investment in Maven infrastructure by adding lines like these into your build.gradle:

# Tell it to look in Maven Central
repositories {
    mavenCentral()
}

# We need darwinsys-api for compiling as well as JUnit for testing
dependencies {
    compile group: 'com.darwinsys', name: 'darwinsys-api', version: '1.0.3+'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

See Also

There is much more functionality in Gradle. Start at Gradle’s website, and see the documentation.

Dealing with Deprecation Warnings

Problem

Your code used to compile cleanly, but now it gives deprecation warnings.

Solution

You must have blinked. Either live—dangerously—with the warnings, or revise your code to eliminate them.

Discussion

Each new release of Java includes a lot of powerful new functionality, but at a price: during the evolution of this new stuff, Java’s maintainers find some old stuff that wasn’t done right and shouldn’t be used anymore because they can’t really fix it. In the first major revision, for example, they realized that the java.util.Date class had some serious limitations with regard to internationalization. Accordingly, many of the Date class methods and constructors are marked “deprecated.” According to the American Heritage Dictionary, to deprecate something means to “express disapproval of; deplore.” Java’s developers are therefore disapproving of the old way of doing things. Try compiling this code:

import java.util.Date;

/** Demonstrate deprecation warning */
public class Deprec {

    public static void main(String[] av) {

        // Create a Date object for May 5, 1986
        Date d =
            new Date(86, 04, 05);    // EXPECT DEPRECATION WARNING
        System.out.println("Date is " + d);
    }
}

What happened? When I compile it, I get this warning:

C:\javasrc>javac Deprec.java
Note: Deprec.java uses or overrides a deprecated API.  Recompile with
"-deprecation" for details.
1 warning
C:\javasrc>

So, we follow orders. For details, recompile with -deprecation (if using Ant, use <javac deprecation= true…>):

C:\javasrc>javac -deprecation Deprec.java
Deprec.java:10: warning: constructor Date(int,int,int) in class java.util.Date
has been deprecated
                Date d = new Date(86, 04, 05);          // May 5, 1986
                         ^
1 warning

C:\javasrc>

The warning is simple: the Date constructor that takes three integer arguments has been deprecated. How do you fix it? The answer is, as in most questions of usage, to refer to the javadoc documentation for the class. The introduction to the Date page says, in part:

The class Date represents a specific instant in time, with millisecond precision.

Prior to JDK 1.1, the class Date had two additional functions. It allowed the interpretation of dates as year, month, day, hour, minute, and second values. It also allowed the formatting and parsing of date strings. Unfortunately, the API for these functions was not amenable to internationalization. As of JDK 1.1, the Calendar class should be used to convert between dates and time fields and the DateFormat class should be used to format and parse date strings. The corresponding methods in Date are deprecated.

And more specifically, in the description of the three-integer constructor, the Date javadoc says:

Date(int year, int month, int date)

Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date) or GregorianCalendar(year + 1900, month, date).

As a general rule, when something has been deprecated, you should not use it in any new code and, when maintaining code, strive to eliminate the deprecation warnings.

In addition to Date (Java 8 includes a whole new Date and Time API; see Chapter 6), the main areas of deprecation warnings in the standard API are the really ancient “event handling” and some methods (a few of them important) in the Thread class.

You can also deprecate your own code, when you come up with a better way of doing things. Put an @Deprecated annotation immediately before the class or method you wish to deprecate and/or use a @deprecated tag in a javadoc comment (see Documenting Classes with Javadoc). The javadoc comment allows you to explain the deprecation, whereas the annotation is easier for some tools to recognize because it is present at runtime (so you can use Reflection (see Chapter 23).

See Also

Numerous other tools perform extra checking on your Java code. See my book Checking Java Programs with Open Source Tools (O’Reilly).

Conditional Debugging Without #ifdef

Problem

You want conditional compilation and Java doesn’t seem to provide it.

Solution

Use constants, command-line arguments, or assertions (see Maintaining Program Correctness with Assertions), depending upon the goal.

Discussion

Some older languages such as C, PL/I, and C++ provide a feature known as conditional compilation. Conditional compilation means that parts of the program can be included or excluded at compile time based upon some condition. One thing it’s often used for is to include or exclude debugging print statements. When the program appears to be working, the developer is struck by a fit of hubris and removes all the error checking. A more common rationale is that the developer wants to make the finished program smaller—a worthy goal—or make it run faster by removing conditional statements.

Conditional compilation?

Although Java lacks any explicit conditional compilation, a kind of conditional compilation is implicit in the language. All Java compilers must do flow analysis to ensure that all paths to a local variable’s usage pass through a statement that assigns it a value first, that all returns from a function pass out via someplace that provides a return value, and so on. Imagine what the compiler will do when it finds an if statement whose value is known to be false at compile time. Why should it even generate code for the condition? True, you say, but how can the results of an if statement be known at compile time? Simple: through final boolean variables. Further, if the value of the if condition is known to be false, the body of the if statement should not be emitted by the compiler either. Presto—instant conditional compilation!

This is shown in the following code:

// IfDef.java
final boolean DEBUG = false;
System.out.println("Hello, World ");
if (DEBUG) {
        System.out.println("Life is a voyage, not a destination");
}

Compilation of this program and examination of the resulting class file reveals that the string “Hello” does appear, but the conditionally printed epigram does not. The entire println has been omitted from the class file. So Java does have its own conditional compilation mechanism:

darian$ jr IfDef
 javac IfDef.java
 java IfDef
Hello, World
darian$ strings IfDef.class | grep Life # not found!
darian$ javac IfDef.java # try another compiler
darian$ strings IfDef.class | grep Life # still not found!
darian$

What if we want to use debugging code similar to this but have the condition applied at runtime? We can use System.properties (see Getting Information from System Properties) to fetch a variable. Instead of using this conditional compilation mechanism, you may want to leave your debugging statements in the code but enable them only at runtime when a problem surfaces. This is a good technique for all but the most compute-intensive applications, because the overhead of a simple if statement is not all that great. Let’s combine the flexibility of runtime checking with the simple if statement to debug a hypothetical fetch() method (part of Fetch.java):

String name = "poem";
if (System.getProperty("debug.fetch") != null) {
    System.err.println("Fetching " + name);
}
value = fetch(name);

Then, we can compile and run this normally and the debugging statement is omitted. But if we run it with a -D argument to enable debug.fetch, the printout occurs:

> java starting.Fetch# See? No output
> java -Ddebug.fetch starting.Fetch
Fetching poem
>

Of course this kind of if statement is tedious to write in large quantities. I originally encapsulated it into a Debug class, which remains part of my com.darwinsys.util package. However, I currently advise the use of a full-function logging package such as java.util.logging (see Network Logging with java.util.logging), Log4J (see Network Logging with log4j), or similar.

This is as good a place as any to interject about another feature—inline code generation. The C/C++ world has a language keyword inline, which is a hint to the compiler that the function (method) is not needed outside the current source file. Therefore, when the C compiler is generating machine code, a call to the function marked with inline can be replaced by the actual method body, eliminating the overhead of pushing arguments onto a stack, passing control, retrieving parameters, and returning values. In Java, making a method final enables the compiler to know that it can be inlined, or emitted in line. This is an optional optimization that the compiler is not obliged to perform, but may for efficiency.

See Also

Maintaining Program Correctness with Assertions.

“Conditional compilation” is used in some languages to enable or disable the printing or “logging” of a large number of debug or informational statements. In Java, this is normally the function of a “logger” package. Some of the common logging mechanisms—including ones that can log across a network connection—are covered in Recipes , , and .

Maintaining Program Correctness with Assertions

Problem

You want to leave tests in your code but not have runtime checking overhead until you need it.

Solution

Use the Java assertion mechanism.

Discussion

The Java language assert keyword takes two arguments separated by a colon (by analogy with the conditional operator): an expression that is asserted by the developer to be true, and a message to be included in the exception that is thrown if the expression is false. Normally, assertions are meant to be left in place (unlike quick-and-dirty print statements, which are often put in during one test and then removed). To reduce runtime overhead, assertion checking is not enabled by default; it must be enabled explicitly with the -enableassertions (or -ea) command-line flag. Here is a simple demo program that shows the use of the assertion mechanism:

testing/AssertDemo.java

public class AssertDemo {
    public static void main(String[] args) {
        int i = 4;
        if (args.length == 1) {
            i = Integer.parseInt(args[0]);
        }
        assert i > 0 : "i is non-positive";
        System.out.println("Hello after an assertion");
    }
}
$ javac -d . testing/AssertDemo.java 
$ java testing.AssertDemo -1
Hello after an assertion
$ java -ea testing.AssertDemo -1
Exception in thread "main" java.lang.AssertionError: i is non-positive
        at AssertDemo.main(AssertDemo.java:15)
$

Debugging with JDB

Problem

The use of debugging printouts and assertions in your code is still not enough.

Solution

Use a debugger, preferably the one that comes with your IDE.

Discussion

The JDK includes a command-line–based debugger, jdb, and all mainstream IDEs include their own debugging tools. If you’ve focused on one IDE, learn to use the debugger that it provides. If you’re a command-line junkie, you may want to learn at least the basic operations of jdb.

Here is a buggy program. It intentionally has bugs introduced so that you can see their effects in a debugger:

starting/Buggy.java

/** This program exhibits some bugs, so we can use a debugger */
public class Buggy {
    static String name;

    public static void main(String[] args) {
        int n = name.length();    // bug # 1
        System.out.println(n);

        name += "; The end.";    // bug #2
        System.out.println(name); // #3
    }
}

Here is a session using jdb to find these bugs:

$ java starting.Buggy
Exception in thread "main" java.lang.NullPointerException
        at Buggy.main(Compiled Code)
$ jdb starting/Buggy
Initializing jdb...
0xb2:class(Buggy)
> run
run Buggy
running ...
main[1]
Uncaught exception: java.lang.NullPointerException
        at Buggy.main(Buggy.java:6)
        at sun.tools.agent.MainThread.runMain(Native Method)
        at sun.tools.agent.MainThread.run(MainThread.java:49)

main[1] list
2          public class Buggy {
3               static String name;
4
5               public static void main(String[] args) {
6       =>              int n = name.length( );  // bug # 1
7
8                       System.out.println(n);
9
10                      name += "; The end.";   // bug #2
main[1] print Buggy.name
Buggy.name = null
main[1] help
** command list **
threads [threadgroup]     -- list threads
thread <thread id>        -- set default thread
suspend [thread id(s)]    -- suspend threads (default: all)
resume [thread id(s)]     -- resume threads (default: all)
where [thread id] | all   -- dump a thread's stack
wherei [thread id] | all  -- dump a thread's stack, with pc info
threadgroups              -- list threadgroups
threadgroup <name>        -- set current threadgroup

print <id> [id(s)]        -- print object or field
dump <id> [id(s)]         -- print all object information

locals                    -- print all local variables in current stack frame

classes                   -- list currently known classes
methods <class id>        -- list a class's methods

stop in <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method
stop at <class id>:<line> -- set a breakpoint at a line
up [n frames]             -- move up a thread's stack
down [n frames]           -- move down a thread's stack
clear <class id>.<method>[(argument_type,...)]  -- clear a breakpoint in a method
clear <class id>:<line>   -- clear a breakpoint at a line
step                      -- execute current line
step up                   -- execute until current method returns to its caller
stepi                     -- execute current instruction
next                      -- step one line (step OVER calls)
cont                      -- continue execution from breakpoint

catch <class id>          -- break for the specified exception
ignore <class id>         -- ignore when the specified exception

list [line number|method] -- print source code
use [source file path]    -- display or change the source path

memory                    -- report memory usage
gc                        -- free unused objects

load classname            -- load Java class to be debugged
run <class> [args]        -- start execution of a loaded Java class
!!                        -- repeat last command
help (or ?)               -- list commands
exit (or quit)            -- exit debugger
main[1] exit
$

Other debuggers are available; some of them can even work remotely because the Java Debugger API (which the debuggers use) is network based. Most IDEs feature their own debugging tools; you may want to spend some time becoming familiar with the tools in your chosen IDE.

Avoiding the Need for Debuggers with Unit Testing

Problem

You don’t want to have to debug your code.

Solution

Use unit testing to validate each class as you develop it.

Discussion

Stopping to use a debugger is time consuming; it’s better to test beforehand. The methodology of unit testing has been around for a long time; it is a tried-and-true means of getting your code tested in small blocks. Typically, in an OO language like Java, unit testing is applied to individual classes, in contrast to “system” or “integration” testing where the entire application is tested.

I have long been an advocate of this very basic testing methodology. Indeed, developers of the software methodology known as Extreme Programming (XP for short) advocate “Test Driven Development” (TDD): writing the unit tests before you write the code. They also advocate running your tests almost every time you build your application. And they ask one good question: If you don’t have a test, how do you know your code (still) works? This group of unit-testing advocates has some well-known leaders, including Erich Gamma of Design Patterns book fame and Kent Beck of eXtreme Programming book fame. I definitely go along with their advocacy of unit testing.

Indeed, many of my classes used to come with a “built-in” unit test. Classes that are not main programs in their own right would often include a main method that just tests out the functionality of the class. What surprised me is that, before encountering XP, I used to think I did this often, but an actual inspection of two projects indicated that only about a third of my classes had test cases, either internally or externally. Clearly what is needed is a uniform methodology. That is provided by JUnit.

JUnit is a Java-centric methodology for providing test cases that you can download for free. JUnit is a very simple but useful testing tool. It is easy to use—you just write a test class that has a series of methods and annotate them with @Test (the older JUnit 3.8 required you to have test methods’ names begin with test). JUnit uses introspection (see Chapter 23) to find all these methods, and then runs them for you. Extensions to JUnit handle tasks as diverse as load testing and testing enterprise components; the JUnit website provides links to these extensions. All modern IDEs provide built-in support for generating and running JUnit tests.

How do you get started using JUnit? All that’s necessary is to write a test. Here I have written a simple test of my Person class and placed it into a class called PersonTest (note the obvious naming pattern):

public class PersonTest {

    @Test
    public void testNameConcat() {
        Person p = new Person("Ian", "Darwin");
        String f = p.getFullName();
        assertEquals("Name concatenation", "Ian Darwin", f);
    }
}

To run it manually, I compile the test and invoke the command-line test harness TestRunner:

$ javac PersonTest.java
$ java -classpath junit4.x.x.jar junit.textui.TestRunner testing.PersonTest
.
Time: 0.188

OK (1 tests)

$

In fact, running that is tedious, so I usually have a regress target in my Ant scripts. There is a junit task in Ant’s “Optional Tasks” package.[7] Using it is easy:

<target  name="regress" depends="build">
    <junit>
          <test name="PersonTest" />
    </junit>
</target>

In fact, even that is tedious, so nowadays I just put my tests in the “standard directory structure” (i.e., src/test/java/) with the same package as the code being tested, and run Maven (see Automating Dependencies, Compilation, Testing, and Deployment with Apache Maven), which will automatically compile and run all the unit tests, and halt the build if any test fails.

The Hamcrest matchers allow you to write more expressive tests, at the cost of an additional download. Support for them is built into JUnit 4 with the assertThat static method, but you need to download the matchers from Hamcrest or via the Maven artifact.

Here’s an example of using the Hamcrest Matchers:

public class HamcrestDemo {

    @Test
    public void testNameConcat() {
        Person p = new Person("Ian", "Darwin");
        String f = p.getFullName();
        assertThat(f, containsString("Ian"));
        assertThat(f, equalTo("Ian Darwin"));
        assertThat(f, not(containsString("/"))); // contrived, to show syntax
    }
}

See Also

If you prefer flashier GUI output, several JUnit variants (built using Swing and AWT; see Chapter 14) will run the tests with a GUI. More importantly, all modern IDEs provide built-in support for running tests; in Eclipse, you can right-click a project in the Package Explorer and select Run As→Unit Test to have it find and run all the JUnit tests in the entire project.

JUnit offers considerable documentation of its own; download it from the website listed earlier.

Also, for manual testing of graphical components, I have developed a simple component tester, described in Showing Graphical Components Without Writing Main.

An alternative Unit Test framework for Java is TestNG; it got some early traction by adopting Java annotations before JUnit did, but since JUnit got with the annotations program, JUnit has remained the dominant package for Java Unit Testing.

Remember: Test early and often!

Maintaining Your Code with Continuous Integration

Problem

You want to be sure that your entire code base compiles and passes its tests periodically.

Solution

Use a Continuous Integration server such as Jenkins/Hudson.

Discussion

If you haven’t previously used continuous integration, you are going to wonder how you got along without it. CI is simply the practice of having all developers on a project periodically integrate their changes into a single master copy of the project’s “source.” This might be a few times a day, or every few days, but should not be more than that, else the integration will likely run into larger hurdles where multiple developers have modified the same file.

But it’s not just big projects that benefit from CI. Even on a one-person project, it’s great to have a single button you can click that will check out the latest version of everything, compile it, link or package it, run all the automated tests, and give a red or green pass/fail indicator.

And it’s not just code-based projects that benefit from CI. If you have a number of small websites, putting them all under CI control is one of several important steps toward developing an automated, “dev-ops” culture around website deployment and management.

If you are new to the idea of CI, I can do no better than to plead with you to read Martin Fowler’s insightful (as ever) paper on the topic. One of the key points is to automate both the management of the code and all the other artifacts needed to build your project, and to automate the actual process of building it, possibly using one of the build tools discussed earlier in this chapter.[8]

There are many CI servers, both free and commercial. In the open source world, CruiseControl and Jenkins/Hudson are among the best known. Jenkins/Hudson began as Hudson, largely written by Kohsuke Kawaguchi, while working for Sun Microsystems. Unsurprising, then, that he wrote it in Java. Not too surprising, either, that when Oracle took over Sun, there were some cultural clashes over this project, like many other open source projects,[9] with the key players (includine Kohsuke) packing up and moving on, creating a new “fork” or split of the project. Kohsuke works on the half now known as Jenkins (for a long time, each project regarded itself as the real project and the other as the fork). Hereafter, I’ll just use the name Jenkins, because that’s the one I use, and because it takes too long to say “Jenkins/Hudson” all the time. But almost everything here applies to Hudson as well.

Jenkins is a web application; once it’s started, you can use any standard web browser as its user interface. Installing and starting Jenkins can be as simple as unpacking a distribution and invoking it as follows:

java -jar jenkins.war

If you do that, be sure to enable security if your machine is on the Internet! This will start up its own tiny web server. Many people find it more secure to run Jenkins in a full-function Java EE or Java web server; anything from Tomcat to JBoss to WebSphere or Weblogic will do the job, and let you impose additional security constraints.

Once Jenkins is up and running and you have enabled security and are logged in on an account with sufficient privilege, you can create “jobs.” A job usually corresponds to one project, both in terms of origin (one source code checkout) and in terms of results (one war file, one executable, one library, one whatever). Setting up a project is as simple as clicking the “New Job” button at the top-left of the dashboard, as shown in Figure 1-12.

Jenkins: Dashboard
Figure 1-12. Jenkins: Dashboard

You can fill in the first few pieces of information: the project’s name and a brief description. Note that each and every input field has a “?” Help icon beside it, which will give you hints as you go along. Don’t be afraid to peek at these hints! Figure 1-13 shows the first few steps of setting up a new job.

Jenkins: Starting a new job
Figure 1-13. Jenkins: Starting a new job

In the next few sections of the form, Jenkins uses dynamic HTML to make entry fields appear based on what you’ve checked. My demo project “TooSmallToFail” starts off with no source code management (SCM) repository, but your real project is probably already in Git, Subversion, or maybe even CVS or some other SCM. Don’t worry if yours is not listed; there are hundreds of plug-ins to handle almost any SCM. Once you’ve chosen your SCM, you will enter the parameters to fetch the project’s source from that SCM repository, using text fields that ask for the specifics needed for that SCM: a URL for Git, a CVSROOT for CVS, and so on.

You also have to tell Jenkins when and how to build (and package, test, deploy…) your project. For the when, you have several choices such as building it after another Jenkins project, building it every so often based on a cron-like schedule, or based on polling the SCM to see if anything has changed (using the same cron-like scheduler). If your project is at GitHub (not just a local Git server), or some other SCMs, you can have the project built whenever somebody pushes changes up to the repository. It’s all a matter of finding the right plug-ins and following the documentation for them.

Then the how, or the build process. Again, a few build types are included with Jenkins, and many more are available as plug-ins: I’ve used Apache Ant, Apache Maven, Gradle, the traditional Unix make tool, and even shell or command lines. As before, text fields specific to your chosen tool will appear once you select the tool. In the toy example, TooSmallToFail, I just use the shell command /bin/false (which should be present on any Unix or Linux system) to ensure that the project does, in fact, fail to build, just so you can see what that looks like.

You can have zero or more build steps; just keep clicking the Add button and add additional ones, as shown in Figure 1-14.

Jenkins: Dynamic web page for SCM and adding build steps
Figure 1-14. Jenkins: Dynamic web page for SCM and adding build steps

Once you think you’ve entered all the necessary information, click the Save button at the bottom of the page, and you’ll go back to the project’s main page. Here you can click the funny little “build now” icon at the far left to initiate a build right away. Or if you have set up build triggers, you could wait until they kick in, but then again, wouldn’t you rather know right away whether you’ve got it just right? Figure 1-15 shows the build starting.

Jenkins: After a new job is added
Figure 1-15. Jenkins: After a new job is added

Should a job fail to build, you get a red ball instead of a green one. Actually, success shows a blue ball by default, but most people here prefer green for success, so the optional “Green Ball” plug-in is usually one of the first to be added to a new installation.

Beside the red or green ball, you will see a “weather report” ranging from sunny (the last several builds have succeeded), cloudy, rainy, or stormy (no recent builds have succeeded).

Click the link to the project that failed, and then the link to Console Output, and figure out what went wrong. The usual workflow is then to make changes to the project, commit/push them to the source code repository, and run the Jenkins build again.

As mentioned, there are hundreds of optional plug-ins for Jenkins. To make your life easier, almost all of them can be installed by clicking the Manage Jenkins link and then going to Manage Plug-ins. The Available tab lists all the ones that are available from Jenkins.org; you just need to click the checkbox beside the ones you want, and click Apply. You can also find updates here. If your plug-in addtion or upgrade requires a restart, you’ll see a yellow ball and words to that effect; otherwise you should see a green (or blue) ball indicating plug-in success. You can also see the list of plug-ins directly on the Web.

I mentioned that Jenkins began life under the name Hudson. The Hudson project still exists, and is hosted at the Eclipse website. Last I checked, both projects had maintained plug-in compatibility, so many or most plug-ins from one can be used with the other. In fact, the most popular plug-ins appear in the Available tab of both, and most of what’s said in this recipe about Jenkins applies equally to Hudson. If you use a different CI system, you’ll need to check that system’s documentation, but the concepts and the benefits will be similar.

Getting Readable Tracebacks

Problem

You’re getting an exception stack trace at runtime, but most of the important parts don’t have line numbers.

Solution

Be sure you have compiled with debugging enabled. On older systems, disable JIT and run it again, or use the current HotSpot runtime.

Discussion

When a Java program throws an exception, the exception propagates up the call stack until there is a catch clause that matches it. If none is found, the Java interpreter program that invoked your main() method catches the exception and prints a stack traceback showing all the method calls that got from the top of the program to the place where the exception was thrown. You can print this traceback yourself in any catch clause: the Throwable class has several methods called printStackTrace().

The traceback includes line numbers only if they were compiled in. When using javac, this is the default. When using Ant’s javac task, this is not the default; you must be sure you have used <javac debug="true" …> in your build.xml file if you want line numbers.

Finding More Java Source Code: Programs, Frameworks, Libraries

Problem

You want to build a large application and need to minimize coding, avoiding the “Not Invented Here” syndrome.

Solution

Use the Source, Luke. There are thousands of Java apps, frameworks, and libraries available in open source.

Discussion

Java source code is everywhere. As mentioned in the Preface, all the code examples from this book can be downloaded from the book’s catalog page.

Another valuable resource is the source code for the Java API. You may not have realized it, but the source code for all the public parts of the Java API are included with each release of the Java Development Kit. Want to know how java.util.ArrayList actually works? You have the source code. Got a problem making a JTable behave? The standard JDK includes the source for all the public classes! Look for a file called src.zip or src.jar; some versions unzip this and some do not.

If that’s not enough, you can get the source for the whole JDK for free over the Internet, just by committing to the Sun Java Community Source License and downloading a large file. This includes the source for the public and nonpublic parts of the API, as well as the compiler (written in Java) and a large body of code written in C/C++ (the runtime itself and the interfaces to the native library). For example, java.io.Reader has a method called read(), which reads bytes of data from a file or network connection. This is written in C because it actually calls the read() system call for Unix, Windows, Mac OS, BeOS, or whatever. The JDK source kit includes the source for all this stuff.

And ever since the early days of Java, a number of websites have been set up to distribute free software or open source Java, just as with most other modern “evangelized” languages, such as Perl, Python, Tk/Tcl, and others. (In fact, if you need native code to deal with some oddball filesystem mechanism in a portable way, beyond the material in Chapter 11, the source code for these runtime systems might be a good place to look.)

Although most of this book is about writing Java code, this recipe is about not writing code, but about using code written by others. There are hundreds of good frameworks to add to your Java application—why reinvent the flat tire when you can buy a perfectly round one? Many of these frameworks have been around for years and have become well rounded by feedback from users.

What, though, is the difference between a library and a framework? It’s sometimes a bit vague, but in general, a framework is “a program with holes that you fill in,” whereas a library is code you call. It is roughly the difference between building a car by buying a car almost complete but with no engine, and building a car by buying all the pieces and bolting them together yourself.

When considering using a third-party framework, there are many choices and issues to consider. One is cost, which gets into the issue of open source versus closed source. Most “open source” tools can be downloaded for free and used, either without any conditions or with conditions that you must comply with. There is not the space here to discuss these licensing issues, so I will refer you to Understanding Open Source and Free Software Licensing (O’Reilly).

Some well-known collections of open source frameworks and libraries for Java are listed in Table 1-3. Most of the projects on these sites are “curated”—that is, judged and found worthy—by some sort of community process.

Table 1-3. Reputable open source Java collections
OrganizationURLNotes

Apache Software Foundation

http://projects.apache.org

Not just a web server!

Spring framework

http://spring.io/projects

JBoss community

http://www.jboss.org/projects

Not just a Java EE app server!

There are also a variety of open source code repositories, which are not curated—anybody who signs up can create a project there, regardless of the existing community size (if any). Sites like this that are successful accumulate too many projects to have a single page listing them—you have to search. Most are not specific to Java. Table 1-4 shows some of the open source code repos.

Table 1-4. Open source code repositories
NameURLNotes

Sourceforge.net

http://sourceforge.net/

One of the oldest

GitHub

http://github.com/

“Social Coding”

Google Code

http://code.google.com/p

java.net

http://dev.java.net/

Java-specific; sponsored by Sun, now Oracle

That is not to disparage these—indeed, the collection of demo programs for this book is hosted on GitHub—but only to say that you have to know what you’re looking for, and exercise a bit more care before deciding on a framework. Is there a community around it, or is it a dead end?

Finally, the author of this book maintains a small Java site, which may be of value. It includes a listing of Java resources and material related to this book.

For the Java enterprise or web tier, there are two main frameworks that also provide “dependency injection”: JavaServer Faces (JSF) and CDI, and the Spring Framework “SpringMVC” package. JSF and the built-in CDI (Contexts and Dependency Injection) provides DI as well as some additional Contexts, such as a very useful Web Conversation context that holds objects across multiple web page interactions. The Spring Framework provides dependency injection and the SpringMVC web-tier helper classes. Table 1-5 shows some web tier resources.

Table 1-5. Web tier resources
NameURLNotes

Ians List of 100 Java Web Frameworks

http://darwinsys.com/jwf/

JSF

http://bit.ly/1lCLULS

Java EE new standard technology for web pages

Because JSF is a component-based framework, there are many add-on components that will make your JSF-based website much more capable (and better looking) than the default JSF components. Table 1-6 shows some of the JSF add-on libraries.

Table 1-6. JSF add-on libraries
NameURLNotes

PrimeFaces

http://primefaces.org/

Rich components library

RichFaces

http://richfaces.org/

Rich components library

OpenFaces

http://openfaces.org/

Rich components library

IceFaces

http://icefaces.org/

Rich components library

Apache Deltaspike

http://deltaspike.apache.org/

Numerous code add-ons for JSF

JSFUnit

http://www.jboss.org/jsfunit/

JUnit Testing for JSFUnit

There are frameworks and libraries for almost everything these days. If my lists don’t lead you to what you need, a web search probably will. Try not to reinvent the flat tire!

As with all free software, be sure that you understand the ramifications of the various licensing schemes. Code covered by the GPL, for example, automatically transfers the GPL to any code that uses even a small part of it. Consult a lawyer. Your mileage may vary. Despite these caveats, the source code is an invaluable resource to the person who wants to learn more Java.



[7] In some versions of Ant, you may need an additional download for this to function.

[8] If the deployment or build includes a step like “Get Smith to process file X on his desktop and copy to the server,” you aren’t automated.

[9] See also Open Office/Libre Office and MySql/mariadb, both involving Oracle.

Get Java Cookbook, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.