Skip to content

Explain the fix when formatDiff hits the jdk.compiler IllegalAccessError #19

Description

@abashev

What happens

In a build that only applies dev.openjavaformat.java-format, ./gradlew formatDiff fails with a raw JVM error:

Execution failed for task ':formatDiff' (registered by plugin 'dev.openjavaformat.java-format').
> class com.palantir.javaformat.java.JavaInput (in unnamed module @0x…) cannot access class
  com.sun.tools.javac.parser.Tokens$TokenKind (in module jdk.compiler) because module jdk.compiler
  does not export com.sun.tools.javac.parser to unnamed module @0x…

Nothing in it tells the user what to change.

Why

The Java-based formatter runs inside the Gradle daemon, and a plain daemon JVM does not export javac's internal packages. FormatDiff.format catches IOException and FormatterException only, so the IllegalAccessError goes straight up to Gradle.

Both known fixes work. Checked with plugin 2.98.0.1, Gradle 9.7.1 and Temurin 21:

  • openjavaformat.native.formatter=true in gradle.properties, on Linux with glibc and on macOS;
  • the five --add-exports jdk.compiler/com.sun.tools.javac.{api,file,parser,tree,util}=ALL-UNNAMED flags in org.gradle.jvmargs, as this repository's own gradle.properties has them.

Proposal

Make formatDiff fail with a message that names both settings and links to https://openjavaformat.dev/get-started/gradle/.

Two ways to get there:

  • catch IllegalAccessError around formatter.getFormatReplacements(...) and rethrow it as a GradleException with that message, or
  • check up front whether jdk.compiler exports com.sun.tools.javac.parser to the formatter's class loader, and fail before the first file. This also avoids printing Formatting <file> for a run that cannot succeed.

The native path is not affected and needs no change.

Reproduce

// build.gradle
plugins {
    id 'java'
    id 'dev.openjavaformat.java-format' version '2.98.0.1'
}

repositories {
    mavenCentral()
}

Commit a Java file, edit it, and run ./gradlew formatDiff with no gradle.properties.

Done when

  • the failure names both settings and the page above;
  • it is checked in a real consumer build against a published or locally published plugin, not only with TestKit.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions