Skip to content
David Bürgin edited this page Nov 7, 2015 · 38 revisions

Setup

Let’s set things up and get started. I’m assuming you have the following ready.

  • Java 8
  • Maven
  • a text editor or IDE you're comfortable with

I’m running the command-line commands in a Unix-like environment – give or take some minor adjustments this tutorial should also work on Windows.

Get the code

Clone this repository, then check out the initial commit. I have tagged it as initial.

git clone https://github.com/glts/safer-spring-petclinic.git
git checkout initial

This is our codebase. Now is a good time to check if we're starting out all green. Before we do this let's make a first commit e7ab16a and upgrade to Java 8.

Run the install Maven goal to see if the build is fine. (This compiles the production and test source, runs the tests, bundles up the WAR artefact run, and installs it in the local Maven repository.)

mvn install

The first time this can take quite a while because all the project's dependencies need to be downloaded. You should see the 'BUILD SUCCESS' message at some point.

Then start the web server:

mvn tomcat7:run

Open a browser at http://localhost:9966/petclinic/. This is the Pet Clinic.

You can browse around a little to get familiar with the app. Hit Control-C to stop the web server when you're done.

Maven

We're going to do this a bit differently from the suggested installation at Checker Framework: compilation with checking is going to be separate from compilation for production.

The class files produced by the Checker Framework's compiler with annotation processing are different from the class files output by the standard compiler. This may not be an issue depending on your situation. With annotation-heavy frameworks like Spring and Hibernate there is a possibility of friction -- as it is here: I did not manage to run the code produced by the Checker Framework compiler.

Furthermore, it goes without saying that in many professional Java environments compiling with a different compiler is not an option. And if you're trying to convince your colleagues to get into checking, making it optional might actually be a boon.

Annotations

Instead of the Checker Framework's nullness annotations I'm going to use the ones from JSR 305. javax.annotation.Nullable is less powerful than its sibling org.checkerframework.checker.nullness.qual.Nullable though. Only the Checker Framework one supports usage as in List<@Nullable String>.

And of course you might want to try other appetising annotations like @Regex. Don't forget to add the appropriate dependency in your <dependencies> section if you decide to go this route.

Anyway, I'm adding the relevant JAR in the dependencies section in commit 4f7f00c. (Don't worry about the missing <version>, Spring fills that in.)

The checker profile

Now let's create a profile for running the Checker. This is a bit involved, but bear with me. It will pay off in the next chapter.

Add a <profiles> section at the bottom of the POM (pom.xml), right above the final <url> tag.

<profiles>
  <profile>
    <id>checker</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.3</version>
          <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <annotationProcessors>
              <annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
            </annotationProcessors>
            <compilerArgs>
              <arg>-Xbootclasspath/p:${checkerframework.jdk8}</arg>
            </compilerArgs>
          </configuration>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

This is the checker profile. As you can see all this does is hook into the compilation process by adding an annotation processor. The NullnessChecker is the annotation processor that will perform the checking.

The Checker Framework comes with an annotated JDK, and we're putting it on the classpath for the annotation processor. The annotated JDK has all method signatures in the JDK, but annotated with things like @Nullable. The annotated JDK isn't strictly necessary but it does help reduce false positives.

If you know Maven, you'll have noticed that some things are still missing.

...

<properties>
  <checkerframework.jdk8>${org.checkerframework:jdk8:jar}</checkerframework.jdk8>
</properties>

...

<dependencies>
  <dependency>
    <groupId>org.checkerframework</groupId>
    <artifactId>checker</artifactId>
    <version>1.9.7</version>
  </dependency>
  <dependency>
    <groupId>org.checkerframework</groupId>
    <artifactId>jdk8</artifactId>
    <version>1.9.7</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

Clone this wiki locally