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
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
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
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.
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.
In Figure 1-3, we have the opportunity to type in the main class.
In Figure 1-4, we run the main class.
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.
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.
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.
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.
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.
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
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
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.
Repository name | Github.com URL | Package description | Approx. size |
javasrc | Java classes from all APIs | 1,200 classes | |
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.
Package name | Package description |
| A demonstration Ant task |
| Classes for comma-separated values files |
| Classes for dealing with databases in a general way |
| Comparison utilities |
| Generic GUI stuff |
| Classes relating to country codes, provinces/states, and so on |
| Graphics |
| Classes (only one so far) for dealing with HTML |
| Classes for input and output operations, using Java’s underlying I/O classes |
| Java EE JSP tags |
| Classes for dealing with standard features of Java |
| Pessimistic locking API |
| Classes for dealing with email, mainly a convenience class for sending mail |
| Modeling |
| Networking |
| Presentations |
| Reflection |
| Regular expression stuff: an REDemo program, a Grep variant, and so on |
| Security |
| Servlet API helpers |
| Classes for dealing with SQL databases |
| Classes for helping construct and use Swing GUIs |
| A few interesting LayoutManager implementations |
| Test data generators |
| Testing tools |
| Unix helpers |
| A few miscellaneous utility classes |
| 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
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 -->
.
<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
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
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.
#
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
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 theDateFormat
class should be used to format and parse date strings. The corresponding methods inDate
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)
orGregorianCalendar(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
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
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
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.
Maintaining Your Code with Continuous Integration
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.
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.
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.
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.
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.
Organization | URL | Notes |
Apache Software Foundation | Not just a web server! | |
Spring framework | ||
JBoss community | 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.
Name | URL | Notes |
Sourceforge.net | One of the oldest | |
GitHub | “Social Coding” | |
Google Code | ||
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.
Name | URL | Notes |
Ians List of 100 Java Web Frameworks | ||
JSF | 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.
Name | URL | Notes |
PrimeFaces | Rich components library | |
RichFaces | Rich components library | |
OpenFaces | Rich components library | |
IceFaces | Rich components library | |
Apache Deltaspike | Numerous code add-ons for JSF | |
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.