diff --git a/CHANGES.md b/CHANGES.md index cfd1f363fd..7425f8ecc2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,8 +11,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Fixed +- `removeUnusedImports` no longer throws on Java `import module` declarations (`JCModuleImport` ClassCastException). ([#2890](https://github.com/diffplug/spotless/issues/2890)) - Concurrent P2 provisioning (parallel multi-project Gradle fingerprinting of `eclipse()` / `greclipse()` steps) no longer races Solstice's on-disk cache; also `ConfigurationCacheHackList.toString()` no longer evaluates step state (which could re-trigger provisioning while Gradle reports "cannot be serialized"). ([#3004](https://github.com/diffplug/spotless/issues/3004)) ### Changes +- Bump default `google-java-format` version `1.28.0` -> `1.30.0` (first release with `import module` support); require at least `1.30.0` on JVM 25+. - Bump default `adocfmt` version `0.2.0` -> `0.3.1`, which adds table formatting support (`formatTables`, `tableLayout`, `tableMaxLineWidth`, `tableBlankLines`). ## [4.9.0] - 2026-07-27 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 703b2d1756..2b71d3d60b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ diktat-rules = "org.cqfn.diktat:diktat-rules:1.2.5" diktat-runner = "com.saveourtool.diktat:diktat-runner:2.0.0" flexmark-all = "com.vladsch.flexmark:flexmark-all:0.64.8" gherkin-utils = "io.cucumber:gherkin-utils:10.0.0" -google-java-format = "com.google.googlejavaformat:google-java-format:1.28.0" +google-java-format = "com.google.googlejavaformat:google-java-format:1.30.0" gson = "com.google.code.gson:gson:2.14.0" javaparser-symbol-solver-core = "com.github.javaparser:javaparser-symbol-solver-core:3.27.1" ktfmt = "com.facebook:ktfmt:0.63" diff --git a/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java b/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java index c0ca7ad0ce..ffe1ba38fd 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/GoogleJavaFormatStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -121,7 +121,8 @@ private static FormatterStep createInternally(String name, String groupArtifact, private static final Jvm.Support JVM_SUPPORT = Jvm. support(NAME) .addMin(21, "1.17.0") // java 21 requires at least 1.17.0 due to https://github.com/google/google-java-format/issues/898 - .add(17, "1.28.0"); // default version + .addMin(25, "1.30.0") // import module (JEP 511) requires google-java-format >= 1.30.0 (https://github.com/google/google-java-format/issues/1213) + .add(17, "1.30.0"); // default version (1.30.0+ handles `import module` in RemoveUnusedImports) public static String defaultGroupArtifact() { return MAVEN_COORDINATE; diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 169371d109..225a955500 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,9 +4,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Fixed +- `removeUnusedImports` no longer fails on Java `import module` declarations. ([#2890](https://github.com/diffplug/spotless/issues/2890)) - `spotlessCheck` violation message now suggests the correct composite/included-build task path (e.g. `./gradlew :my-utils:spotlessApply`) instead of a bare `spotlessApply` / `:spotlessApply` that does not select included-build tasks. ([#2421](https://github.com/diffplug/spotless/issues/2421)) - Parallel multi-project builds no longer intermittently fail with "Cannot fingerprint input property 'stepsInternalEquality': ConfigurationCacheHackList cannot be serialized" / "Failed to provision P2 dependencies" when using `eclipse()` (or other P2-backed steps). Subprojects now share one deduping P2 provisioner and P2 queries are serialized process-wide. ([#3004](https://github.com/diffplug/spotless/issues/3004)) ### Changes +- Bump default `google-java-format` version `1.28.0` -> `1.30.0` (first release with `import module` support); require at least `1.30.0` on JVM 25+. - Bump default `adocfmt` version `0.2.0` -> `0.3.1`, which adds table formatting support (`formatTables`, `tableLayout`, `tableMaxLineWidth`, `tableBlankLines`). ## [8.9.0] - 2026-07-27 diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index e82e3cfab1..570de5f897 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,8 +4,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Fixed +- `removeUnusedImports` no longer fails on Java `import module` declarations. ([#2890](https://github.com/diffplug/spotless/issues/2890)) - Concurrent P2 provisioning no longer races Solstice's on-disk cache (affects Eclipse-based formatters under parallel builds). ([#3004](https://github.com/diffplug/spotless/issues/3004)) ### Changes +- Bump default `google-java-format` version `1.28.0` -> `1.30.0` (first release with `import module` support); require at least `1.30.0` on JVM 25+. - Document Maven skip properties `spotless.skip`, `spotless.check.skip`, and `spotless.apply.skip`. Goal-specific skips now live on their own mojos so they no longer leak across goals. ([#3009](https://github.com/diffplug/spotless/pull/3009)) - Bump default `adocfmt` version `0.2.0` -> `0.3.1`, which adds table formatting support (``, ``, ``, ``). - Add support to apply alternate license header within same format ([#872](https://github.com/diffplug/spotless/issues/872)) diff --git a/testlib/src/main/resources/java/removeunusedimports/ModuleImportFormatted.test b/testlib/src/main/resources/java/removeunusedimports/ModuleImportFormatted.test new file mode 100644 index 0000000000..86ec1ef298 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/ModuleImportFormatted.test @@ -0,0 +1,10 @@ +import module java.base; +import java.util.ArrayList; +import java.util.List; + +class ModuleImportTest { + void test() { + UUID.randomUUID(); + List list = new ArrayList<>(); + } +} diff --git a/testlib/src/main/resources/java/removeunusedimports/ModuleImportUnformatted.test b/testlib/src/main/resources/java/removeunusedimports/ModuleImportUnformatted.test new file mode 100644 index 0000000000..86ec1ef298 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/ModuleImportUnformatted.test @@ -0,0 +1,10 @@ +import module java.base; +import java.util.ArrayList; +import java.util.List; + +class ModuleImportTest { + void test() { + UUID.randomUUID(); + List list = new ArrayList<>(); + } +} diff --git a/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedFormatted.test b/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedFormatted.test new file mode 100644 index 0000000000..b668944532 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedFormatted.test @@ -0,0 +1,10 @@ +import module java.base; +import java.util.ArrayList; +import java.util.List; + +class ModuleImportWithUnused { + void test() { + UUID.randomUUID(); + List list = new ArrayList<>(); + } +} diff --git a/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedUnformatted.test b/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedUnformatted.test new file mode 100644 index 0000000000..09da6d39f9 --- /dev/null +++ b/testlib/src/main/resources/java/removeunusedimports/ModuleImportWithUnusedUnformatted.test @@ -0,0 +1,11 @@ +import module java.base; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +class ModuleImportWithUnused { + void test() { + UUID.randomUUID(); + List list = new ArrayList<>(); + } +} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java index eaa6b12c7e..e9694bbd63 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/GoogleJavaFormatStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import static org.junit.jupiter.api.condition.JRE.JAVA_20; import static org.junit.jupiter.api.condition.JRE.JAVA_21; +import static org.junit.jupiter.api.condition.JRE.JAVA_25; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; @@ -75,6 +76,15 @@ void versionBelowOneDotTenIsNotAllowed() throws Exception { .toBe("LINE_UNDEFINED google-java-format(jvm-version) You are running Spotless on JVM 21. This requires google-java-format of at least 1.17.0 (you are using 1.9). (...)"); } + @Test + @EnabledForJreRange(min = JAVA_25) + void versionBelowMinOnJava25IsNotAllowed() throws Exception { + FormatterStep step = GoogleJavaFormatStep.create("1.28.0", "AOSP", TestProvisioner.mavenCentral()); + StepHarness.forStepNoRoundtrip(step) + .expectLintsOfResource("java/googlejavaformat/JavaCodeWithLicenseUnformatted.test") + .toBe("LINE_UNDEFINED google-java-format(jvm-version) You are running Spotless on JVM 25. This requires google-java-format of at least 1.30.0 (you are using 1.28.0). (...)"); + } + @Test void behaviorWithAospStyle() throws Exception { FormatterStep step = GoogleJavaFormatStep.create(GoogleJavaFormatStep.defaultVersion(), "AOSP", TestProvisioner.mavenCentral()); diff --git a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java index 84ad3f1f61..bd63822e63 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/RemoveUnusedImportsStep_withGoogleJavaFormatTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package com.diffplug.spotless.java; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.SerializableEqualityTester; @@ -38,6 +40,20 @@ void behavior() throws Exception { ; } + /** + * {@code import module} (JEP 511) is only parseable on JDK 25+. google-java-format 1.30+ + * skips module imports in {@code RemoveUnusedImports} instead of ClassCastException on + * {@code JCModuleImport} (https://github.com/diffplug/spotless/issues/2890). + */ + @Test + @EnabledForJreRange(min = JRE.JAVA_25) + void moduleImports() throws Exception { + FormatterStep step = RemoveUnusedImportsStep.create(RemoveUnusedImportsStep.GJF, TestProvisioner.mavenCentral()); + StepHarness.forStep(step) + .testResource("java/removeunusedimports/ModuleImportUnformatted.test", "java/removeunusedimports/ModuleImportFormatted.test") + .testResource("java/removeunusedimports/ModuleImportWithUnusedUnformatted.test", "java/removeunusedimports/ModuleImportWithUnusedFormatted.test"); + } + @Test void equality() throws Exception { new SerializableEqualityTester() {