The Checker Framework

Quoting from the manual:

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs.

A checker” is a compile-time tool that warns you about certain errors or gives you a guarantee that those errors do not occur.

And from Section 1.2 of the manual

The Checker Framework lets you define new type systems and run them as a plug-in to the javac compiler. Your code stays completely backward-compatible: your code compiles with any Java compiler, it runs on any JVM, and your coworkers don’t have to use the enhanced type system if they don’t want to. You can check part of your program, or the whole thing.

How to use with maven and select which checkers to enable

To enable the checker framework with maven, you can find instructions in Section 37.13 of the manual.

For each checker you want to enable, you need to add it as an annotation processor. For example, if you want to enable the NullnessChecker, you would include it in the list.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.8.1</version>
  <configuration>
    <annotationProcessorPaths>
      <path>
        <groupId>org.checkerframework</groupId>
        <artifactId>checker</artifactId>
        <version>3.x.x</version>
      </path>
    </annotationProcessorPaths>
    <annotationProcessors>
      <annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
      <!-- Add other checkers here -->
    </annotationProcessors>
    <compilerArgs>
      <arg>-Xmaxwarns</arg>
      <arg>10000</arg>
    </compilerArgs>
  </configuration>
</plugin>

How to use with gradle

In an (maybe a little old now) project I wrote, I tried using the Kotlin DSL for gradle, and got this working (build.gradle.kts):

import org.checkerframework.gradle.plugin.CheckerFrameworkExtension

plugins {
    id("java")
    id("application")
    id("com.github.ben-manes.versions") version "0.51.0"
    id("io.freefair.lombok") version "8.6"
    id("org.checkerframework") version "0.6.37"
}

group = "mx.oscarvarto"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
    //maven(url = "https://projectlombok.org/edge-releases")
    maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
}

lombok {
    version = "1.18.32"
}

dependencies {
    implementation("org.functionaljava:functionaljava:5.0")
    implementation("com.google.guava:guava:33.1.0-jre")
    implementation("ch.qos.logback:logback-classic:1.5.3")
    implementation("org.slf4j:slf4j-api:2.1.0-alpha1")

    implementation("org.graalvm.polyglot:polyglot:24.0.0")
    implementation("org.graalvm.polyglot:python:24.0.0")
    implementation("org.graalvm.polyglot:tools:24.0.0")
    implementation("org.graalvm.polyglot:dap:24.0.0")

    compileOnly("org.checkerframework:checker-qual:3.43.0-SNAPSHOT")
    testCompileOnly("org.checkerframework:checker-qual:3.43.0-SNAPSHOT")
    checkerFramework("org.checkerframework:checker:3.43.0-SNAPSHOT")
    implementation("org.checkerframework:checker-util:3.43.0-SNAPSHOT")

    testImplementation(platform("org.junit:junit-bom:5.10.2"))
    testImplementation("org.junit.jupiter:junit-jupiter")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    testImplementation("org.assertj:assertj-core:3.25.3")

    compileOnly("org.projectlombok:lombok:1.18.32")
}

java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

application {
    applicationDefaultJvmArgs = listOf("-Astubs=collection-object-parameters-may-be-null.astub")
}

configure<CheckerFrameworkExtension> {
    checkers = listOf(
        "org.checkerframework.checker.nullness.NullnessChecker"
    )
}

tasks.test {
    useJUnitPlatform()
}

Date
September 7, 2024