From 020560ca9ce0d035059ec69b7e90eee0fb033050 Mon Sep 17 00:00:00 2001 From: Alex Abashev Date: Sun, 8 Nov 2026 13:12:41 +0300 Subject: [PATCH] Say the Gradle plugin carries the formatter and needs no root repository The Gradle plugin now carries the formatter's jars inside it (openjavaformat/open-java-format#20): a build declares nothing for the formatter and needs no repository for it. The native binary is resolved by each project that formats, through its own repositories, so the root project of a multi-project build needs none, and parallel builds work. The multi-project example declares its repositories in the subprojects to show that. The Gradle page gains a Build cache section, spotlessJava's key changes with the formatter and holds across directories and machines, and a section on declaring another formatter version in palantirJavaFormat. The Spotless page no longer ties the native property to Java 21, says that a build without the --add-exports flags now fails spotlessJava, and keeps the --rerun-tasks advice for versions up to 21.0.1. To merge with the release that has these changes: until then the pages would promise what the published plugin does not do. --- docs/get-started/gradle.md | 68 +++++++++++++++++++++++++++--------- docs/get-started/spotless.md | 9 +++-- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/docs/get-started/gradle.md b/docs/get-started/gradle.md index 12f20e5..65f9800 100644 --- a/docs/get-started/gradle.md +++ b/docs/get-started/gradle.md @@ -31,7 +31,9 @@ formatter version as the build. It needs Gradle 9 and a Gradle daemon running on } ``` -The formatter itself is downloaded from Maven Central, in the same version as the plugin. +The formatter comes inside the plugin, in the plugin's own version: the build declares nothing for it +and needs no repository for it. The repository above is for the build's own dependencies, and for the +native binary below. ## Choose how the formatter runs @@ -45,7 +47,10 @@ the two settings below; without either, `formatDiff` stops before the first file ``` Gradle then runs the formatter as a native binary, outside its own JVM. This works on Linux - with glibc, on macOS and on Windows on x86-64. + with glibc, on macOS and on Windows on x86-64. The binary, some 60 MB, is + `dev.openjavaformat:open-java-format-native` from Maven Central: each project that formats + resolves it through its own repositories, `mavenCentral()` or a mirror of it, and runs a copy + kept in `~/.gradle/open-java-format-caches`. === "On the Gradle JVM" @@ -74,8 +79,9 @@ With a clean working tree it has nothing to do. ## Multi-project builds -Declare the plugin once in the root project and apply it wherever there is Java code. The formatter -is resolved by the root project, so the root project needs the repository too. +Declare the plugin once in the root project and apply it wherever there is Java code. Each project +resolves what it needs through its own repositories, so the root project needs none; a parallel +build (`--parallel`) works too. === "Groovy" @@ -84,15 +90,13 @@ is resolved by the root project, so the root project needs the repository too. id 'dev.openjavaformat.java-format' version '{{ ojf_version }}' apply false } - allprojects { - repositories { - mavenCentral() - } - } - subprojects { apply plugin: 'java' apply plugin: 'dev.openjavaformat.java-format' + + repositories { + mavenCentral() + } } ``` @@ -103,15 +107,13 @@ is resolved by the root project, so the root project needs the repository too. id("dev.openjavaformat.java-format") version "{{ ojf_version }}" apply false } - allprojects { - repositories { - mavenCentral() - } - } - subprojects { apply(plugin = "java") apply(plugin = "dev.openjavaformat.java-format") + + repositories { + mavenCentral() + } } ``` @@ -131,6 +133,40 @@ Up to 21.0.1, `formatDiff` and the Spotless step fail with the cache on Gradle's own `idea` task does not support the cache, and Gradle turns it off for a build that runs the task. +## Build cache + +The [Spotless](spotless.md) task `spotlessJava` is cacheable, and the formatter is part of its cache +key: another formatter version runs the task again, while a copy of the project in another directory, +or on another machine, takes the result from the cache. A build that cannot run the formatter, for +want of the `--add-exports` flags above, fails `spotlessJava` and leaves nothing in the cache. + +Up to 21.0.1, the key did not change with the formatter version, and a failure of the formatter went +into the cache as the task's result. + +## Another formatter version + +The plugin formats with the version that comes inside it. To try another one, declare it in the root +project. Each project that formats resolves it through its own repositories, and so does the root +project, for the IntelliJ IDEA settings below: + +=== "Groovy" + + ``` groovy title="build.gradle" + dependencies { + palantirJavaFormat 'dev.openjavaformat:open-java-format:' + } + ``` + +=== "Kotlin" + + ``` kotlin title="build.gradle.kts" + dependencies { + "palantirJavaFormat"("dev.openjavaformat:open-java-format:") + } + ``` + +The IntelliJ IDEA settings below then name that version too. + ## IntelliJ IDEA When the project is opened in IntelliJ IDEA, the plugin writes the formatter settings into `.idea`, diff --git a/docs/get-started/spotless.md b/docs/get-started/spotless.md index 7ea42fe..4d18cf7 100644 --- a/docs/get-started/spotless.md +++ b/docs/get-started/spotless.md @@ -39,8 +39,8 @@ that line. ``` The step runs the formatter inside the Gradle JVM, so it needs the `--add-exports` flags. The native -formatter property from the [Gradle plugin](gradle.md) page does not help here: on Java 21 and -later the Spotless step does not use it. +formatter property from the [Gradle plugin](gradle.md) page does not help here: the Spotless step +always runs on the Gradle JVM. ``` properties title="gradle.properties" org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ @@ -55,7 +55,10 @@ org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAME ./gradlew spotlessCheck # fail when a file is not formatted ``` -!!! warning "An error that stays after the fix" +Without the flags `spotlessJava` fails and names them. The step works with Gradle's +[configuration cache and build cache](gradle.md#build-cache), and in parallel builds. + +!!! warning "Up to 21.0.1: an error that stays after the fix" Without the flags the step fails with `NoClassDefFoundError: Could not initialize class com.palantir.javaformat.java.ImportOrderer`. Spotless remembers that result, so after adding