From f08ae2093bb956f57d2219b94f25e5d7ab671aa1 Mon Sep 17 00:00:00 2001 From: Andrew Gustafson <628811+agustafson@users.noreply.github.com> Date: Tue, 30 Jun 2026 16:38:12 +0000 Subject: [PATCH 1/3] Add support for prince-of-space Java formatter Adds io.princeofspace prince-of-space as a Java FormatterStep, following the same JarState + reflection glue pattern used for palantir-java-format and google-java-format. Wires it into the Gradle (princeOfSpace()) and Maven () plugins with all of prince-of-space's FormatterConfig knobs exposed (indentStyle, indentSize, lineLength, wrapStyle, closingParenOnNewLine, trailingCommas, javaLanguageLevel). --- CHANGES.md | 2 + gradle/libs.versions.toml | 1 + lib/build.gradle | 3 + .../spotless/java/PrinceOfSpaceStep.java | 159 ++++++++++++++++++ .../glue/pos/PrinceOfSpaceFormatterFunc.java | 68 ++++++++ plugin-gradle/CHANGES.md | 2 + plugin-gradle/README.md | 20 ++- .../gradle/spotless/JavaExtension.java | 68 ++++++++ plugin-maven/CHANGES.md | 2 + plugin-maven/README.md | 19 ++- .../diffplug/spotless/maven/java/Java.java | 4 + .../spotless/maven/java/PrinceOfSpace.java | 78 +++++++++ .../spotless/java/PrinceOfSpaceStepTest.java | 100 +++++++++++ 13 files changed, 524 insertions(+), 2 deletions(-) create mode 100644 lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java create mode 100644 lib/src/princeOfSpace/java/com/diffplug/spotless/glue/pos/PrinceOfSpaceFormatterFunc.java create mode 100644 plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PrinceOfSpace.java create mode 100644 testlib/src/test/java/com/diffplug/spotless/java/PrinceOfSpaceStepTest.java diff --git a/CHANGES.md b/CHANGES.md index 5b0e8c042a..7a59cf101d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space). ## [4.8.0] - 2026-06-29 ### Added diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8807b1dd4..60f3f847fb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,6 +53,7 @@ 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" palantir-java-format = "com.palantir.javaformat:palantir-java-format:1.1.0" +prince-of-space-core = "io.github.agustafson.princeofspace:prince-of-space-core:2.1.2" scalafmt-core = "org.scalameta:scalafmt-core_2.13:3.8.1" sortpom-sorter = "com.github.ekryd.sortpom:sortpom-sorter:4.0.0" tabletest-formatter-core = "org.tabletest:tabletest-formatter-core:1.1.1" diff --git a/lib/build.gradle b/lib/build.gradle index b4175b2cba..fbfddf163c 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -22,6 +22,7 @@ def NEEDS_GLUE = [ 'ktfmt', 'ktlint', 'palantirJavaFormat', + 'princeOfSpace', 'scalafmt', 'sortPom', 'tableTestFormatter', @@ -117,6 +118,8 @@ dependencies { compatKtLint1Dot0Dot0CompileAndTestOnly libs.slf4j.api // palantirJavaFormat palantirJavaFormatCompileOnly libs.palantir.java.format // this version needs to stay compilable against Java 8 for CI Job testNpm + // princeOfSpace + princeOfSpaceCompileOnly libs.prince.of.space.core // scalafmt scalafmtCompileOnly libs.scalafmt.core // sortPom diff --git a/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java b/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java new file mode 100644 index 0000000000..49deb42225 --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java @@ -0,0 +1,159 @@ +/* + * Copyright 2026 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.java; + +import java.io.Serial; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.util.Objects; + +import javax.annotation.Nullable; + +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.JarState; +import com.diffplug.spotless.Jvm; +import com.diffplug.spotless.Provisioner; + +/** Wraps up prince-of-space as a FormatterStep. */ +public final class PrinceOfSpaceStep implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + private static final String NAME = "prince-of-space"; + public static final String MAVEN_COORDINATE = "io.github.agustafson.princeofspace:prince-of-space-core:"; + public static final String DEFAULT_VERSION = "2.1.2"; + + /** The jar that contains the formatter. */ + private final JarState.Promised jarState; + /** Version of the formatter jar. */ + private final String formatterVersion; + @Nullable private final Options options; + + private PrinceOfSpaceStep(JarState.Promised jarState, String formatterVersion, @Nullable Options options) { + this.jarState = jarState; + this.formatterVersion = formatterVersion; + this.options = options; + } + + /** Creates a step which formats Java source with prince-of-space's default options. */ + public static FormatterStep create(Provisioner provisioner) { + return create(defaultVersion(), provisioner); + } + + /** Creates a step which formats Java source with prince-of-space's default options. */ + public static FormatterStep create(String version, Provisioner provisioner) { + return create(version, provisioner, null); + } + + /** Creates a step which formats Java source with the given options. */ + public static FormatterStep create(String version, Provisioner provisioner, @Nullable Options options) { + Objects.requireNonNull(version, "version"); + Objects.requireNonNull(provisioner, "provisioner"); + return FormatterStep.create(NAME, + new PrinceOfSpaceStep(JarState.promise(() -> JarState.from(MAVEN_COORDINATE + version, provisioner)), version, options), + PrinceOfSpaceStep::equalityState, + State::createFormat); + } + + /** Get default formatter version */ + public static String defaultVersion() { + return DEFAULT_VERSION; + } + + private State equalityState() { + return new State(jarState.get(), formatterVersion, options); + } + + /** Mutable bag of the optional prince-of-space {@code FormatterConfig} knobs; unset (null) fields keep prince-of-space's own defaults. */ + public static class Options implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Nullable private String indentStyle; + @Nullable private Integer indentSize; + @Nullable private Integer lineLength; + @Nullable private String wrapStyle; + @Nullable private Boolean closingParenOnNewLine; + @Nullable private Boolean trailingCommas; + @Nullable private Integer javaLanguageLevel; + + public Options() {} + + public void setIndentStyle(String indentStyle) { + this.indentStyle = indentStyle; + } + + public void setIndentSize(int indentSize) { + this.indentSize = indentSize; + } + + public void setLineLength(int lineLength) { + this.lineLength = lineLength; + } + + public void setWrapStyle(String wrapStyle) { + this.wrapStyle = wrapStyle; + } + + public void setClosingParenOnNewLine(boolean closingParenOnNewLine) { + this.closingParenOnNewLine = closingParenOnNewLine; + } + + public void setTrailingCommas(boolean trailingCommas) { + this.trailingCommas = trailingCommas; + } + + public void setJavaLanguageLevel(int javaLanguageLevel) { + this.javaLanguageLevel = javaLanguageLevel; + } + } + + private static final class State implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + private final JarState jarState; + private final String formatterVersion; + @Nullable private final Options options; + + State(JarState jarState, String formatterVersion, @Nullable Options options) { + if (Jvm.version() < 17) { + throw new IllegalStateException("prince-of-space requires a JDK 17+ host runtime, this JVM is " + Jvm.version()); + } + this.jarState = jarState; + this.formatterVersion = formatterVersion; + this.options = options; + } + + FormatterFunc createFormat() throws Exception { + final ClassLoader classLoader = jarState.getClassLoader(); + final Class formatterFunc = classLoader.loadClass("com.diffplug.spotless.glue.pos.PrinceOfSpaceFormatterFunc"); + final Constructor constructor = formatterFunc.getConstructor( + String.class, Integer.class, Integer.class, String.class, Boolean.class, Boolean.class, Integer.class); + if (options == null) { + return (FormatterFunc) constructor.newInstance(null, null, null, null, null, null, null); + } + return (FormatterFunc) constructor.newInstance( + options.indentStyle, + options.indentSize, + options.lineLength, + options.wrapStyle, + options.closingParenOnNewLine, + options.trailingCommas, + options.javaLanguageLevel); + } + } +} diff --git a/lib/src/princeOfSpace/java/com/diffplug/spotless/glue/pos/PrinceOfSpaceFormatterFunc.java b/lib/src/princeOfSpace/java/com/diffplug/spotless/glue/pos/PrinceOfSpaceFormatterFunc.java new file mode 100644 index 0000000000..3018d5a276 --- /dev/null +++ b/lib/src/princeOfSpace/java/com/diffplug/spotless/glue/pos/PrinceOfSpaceFormatterFunc.java @@ -0,0 +1,68 @@ +/* + * Copyright 2026 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.glue.pos; + +import java.io.File; + +import io.princeofspace.Formatter; +import io.princeofspace.model.FormatterConfig; +import io.princeofspace.model.IndentStyle; +import io.princeofspace.model.JavaLanguageLevel; +import io.princeofspace.model.WrapStyle; + +import com.diffplug.spotless.FormatterFunc; + +public class PrinceOfSpaceFormatterFunc implements FormatterFunc.NeedsFile { + + private final Formatter formatter; + + public PrinceOfSpaceFormatterFunc(String indentStyle, Integer indentSize, Integer lineLength, String wrapStyle, + Boolean closingParenOnNewLine, Boolean trailingCommas, Integer javaLanguageLevel) { + FormatterConfig.Builder builder = FormatterConfig.builder(); + if (indentStyle != null) { + builder.indentStyle(IndentStyle.valueOf(indentStyle)); + } + if (indentSize != null) { + builder.indentSize(indentSize); + } + if (lineLength != null) { + builder.lineLength(lineLength); + } + if (wrapStyle != null) { + builder.wrapStyle(WrapStyle.valueOf(wrapStyle)); + } + if (closingParenOnNewLine != null) { + builder.closingParenOnNewLine(closingParenOnNewLine); + } + if (trailingCommas != null) { + builder.trailingCommas(trailingCommas); + } + if (javaLanguageLevel != null) { + builder.javaLanguageLevel(JavaLanguageLevel.of(javaLanguageLevel)); + } + this.formatter = new Formatter(builder.build()); + } + + @Override + public String applyWithFile(String unix, File file) throws Exception { + return formatter.format(unix, file.toPath()); + } + + @Override + public String toString() { + return "PrinceOfSpaceFormatterFunc{formatter=" + formatter + '}'; + } +} diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 9665b4068c..6309b7eaa5 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `princeOfSpace()` step. ## [8.8.0] - 2026-06-29 ### Added diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 443acf7851..c22a165d1f 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -56,7 +56,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [Git hook (optional)](#git-hook) - [Linting](#linting) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [tabletest-formatter](#tabletest-formatter), [IntelliJ IDEA](#intellij-idea)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [prince-of-space](#prince-of-space), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [tabletest-formatter](#tabletest-formatter), [IntelliJ IDEA](#intellij-idea)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [tabletest-formatter](#tabletest-formatter-1), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -312,6 +312,24 @@ spotless { palantirJavaFormat('2.39.0').formatJavadoc(true) ``` +### prince-of-space + +[homepage](https://github.com/agustafson/prince-of-space). Requires a JDK 17+ host runtime. +```gradle +spotless { + java { + princeOfSpace() + // optional: configure any of the formatter's options + princeOfSpace('2.1.2') + .indentStyle('SPACES') // or 'TABS' + .indentSize(4) + .lineLength(120) + .wrapStyle('BALANCED') // or 'WIDE', 'NARROW' + .closingParenOnNewLine(true) + .trailingCommas(false) + .javaLanguageLevel(17) +``` + ### eclipse jdt [homepage](https://download.eclipse.org/eclipse/downloads/). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 4ea13c261d..4bdbd5266d 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -46,6 +46,7 @@ import com.diffplug.spotless.java.GoogleJavaFormatStep; import com.diffplug.spotless.java.ImportOrderStep; import com.diffplug.spotless.java.PalantirJavaFormatStep; +import com.diffplug.spotless.java.PrinceOfSpaceStep; import com.diffplug.spotless.java.RemoveUnusedImportsStep; import com.diffplug.spotless.java.TableTestFormatterStep; @@ -308,6 +309,73 @@ private FormatterStep createStep() { } } + /** Uses the prince-of-space jar to format source code. */ + public PrinceOfSpaceConfig princeOfSpace() { + return princeOfSpace(PrinceOfSpaceStep.defaultVersion()); + } + + /** Uses the given version of prince-of-space to format source code. */ + public PrinceOfSpaceConfig princeOfSpace(String version) { + Objects.requireNonNull(version); + return new PrinceOfSpaceConfig(version); + } + + public class PrinceOfSpaceConfig { + final String version; + final PrinceOfSpaceStep.Options options = new PrinceOfSpaceStep.Options(); + + PrinceOfSpaceConfig(String version) { + this.version = Objects.requireNonNull(version); + addStep(createStep()); + } + + public PrinceOfSpaceConfig indentStyle(String indentStyle) { + options.setIndentStyle(indentStyle); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig indentSize(int indentSize) { + options.setIndentSize(indentSize); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig lineLength(int lineLength) { + options.setLineLength(lineLength); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig wrapStyle(String wrapStyle) { + options.setWrapStyle(wrapStyle); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig closingParenOnNewLine(boolean closingParenOnNewLine) { + options.setClosingParenOnNewLine(closingParenOnNewLine); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig trailingCommas(boolean trailingCommas) { + options.setTrailingCommas(trailingCommas); + replaceStep(createStep()); + return this; + } + + public PrinceOfSpaceConfig javaLanguageLevel(int javaLanguageLevel) { + options.setJavaLanguageLevel(javaLanguageLevel); + replaceStep(createStep()); + return this; + } + + private FormatterStep createStep() { + return PrinceOfSpaceStep.create(version, provisioner(), options); + } + } + public EclipseConfig eclipse() { return eclipse(EclipseJdtFormatterStep.defaultVersion()); } diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index f2a4a75566..ac83692ad9 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `` step. ## [3.8.0] - 2026-06-29 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 1d0bf6d25f..22e057f9b7 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -40,7 +40,7 @@ user@machine repo % mvn spotless:check - [Git hook (optional)](#git-hook) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [tabletest-formatter](#tabletest-formatter), [IntelliJ IDEA](#intellij-idea)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [prince-of-space](#prince-of-space), [formatAnnotations](#formatAnnotations), [cleanthat](#cleanthat), [tabletest-formatter](#tabletest-formatter), [IntelliJ IDEA](#intellij-idea)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [tabletest-formatter](#tabletest-formatter-1), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -293,6 +293,23 @@ any other maven phase (i.e. compile) then it can be configured as below; ``` +### prince-of-space + +[homepage](https://github.com/agustafson/prince-of-space). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PrinceOfSpace.java). Requires a JDK 17+ host runtime. + +```xml + + 2.1.2 + SPACES + 4 + 120 + BALANCED + true + false + 17 + +``` + ### eclipse jdt [homepage](https://download.eclipse.org/eclipse/downloads/). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Eclipse.java). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index fe6e2633ac..9e31078eea 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -71,6 +71,10 @@ public void addPalantirJavaFormat(PalantirJavaFormat palantirJavaFormat) { addStepFactory(palantirJavaFormat); } + public void addPrinceOfSpace(PrinceOfSpace princeOfSpace) { + addStepFactory(princeOfSpace); + } + public void addRemoveUnusedImports(RemoveUnusedImports removeUnusedImports) { addStepFactory(removeUnusedImports); } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PrinceOfSpace.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PrinceOfSpace.java new file mode 100644 index 0000000000..a862330ad7 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PrinceOfSpace.java @@ -0,0 +1,78 @@ +/* + * Copyright 2026 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.maven.java; + +import org.apache.maven.plugins.annotations.Parameter; + +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.java.PrinceOfSpaceStep; +import com.diffplug.spotless.maven.FormatterStepConfig; +import com.diffplug.spotless.maven.FormatterStepFactory; + +public class PrinceOfSpace implements FormatterStepFactory { + + @Parameter + private String version; + + @Parameter + private String indentStyle; + + @Parameter + private Integer indentSize; + + @Parameter + private Integer lineLength; + + @Parameter + private String wrapStyle; + + @Parameter + private Boolean closingParenOnNewLine; + + @Parameter + private Boolean trailingCommas; + + @Parameter + private Integer javaLanguageLevel; + + @Override + public FormatterStep newFormatterStep(FormatterStepConfig config) { + String version = this.version != null ? this.version : PrinceOfSpaceStep.defaultVersion(); + PrinceOfSpaceStep.Options options = new PrinceOfSpaceStep.Options(); + if (indentStyle != null) { + options.setIndentStyle(indentStyle); + } + if (indentSize != null) { + options.setIndentSize(indentSize); + } + if (lineLength != null) { + options.setLineLength(lineLength); + } + if (wrapStyle != null) { + options.setWrapStyle(wrapStyle); + } + if (closingParenOnNewLine != null) { + options.setClosingParenOnNewLine(closingParenOnNewLine); + } + if (trailingCommas != null) { + options.setTrailingCommas(trailingCommas); + } + if (javaLanguageLevel != null) { + options.setJavaLanguageLevel(javaLanguageLevel); + } + return PrinceOfSpaceStep.create(version, config.getProvisioner(), options); + } +} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/PrinceOfSpaceStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/PrinceOfSpaceStepTest.java new file mode 100644 index 0000000000..853f2e4bee --- /dev/null +++ b/testlib/src/test/java/com/diffplug/spotless/java/PrinceOfSpaceStepTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2026 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.java; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.Formatter; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.LineEnding; +import com.diffplug.spotless.ResourceHarness; +import com.diffplug.spotless.SerializableEqualityTester; +import com.diffplug.spotless.TestProvisioner; + +class PrinceOfSpaceStepTest extends ResourceHarness { + + private static String format(FormatterStep step, String input) { + try (Formatter formatter = Formatter.builder() + .steps(Collections.singletonList(step)) + .lineEndingsPolicy(LineEnding.UNIX.createPolicy()) + .encoding(StandardCharsets.UTF_8) + .build()) { + return formatter.compute(LineEnding.toUnix(input), new File("")); + } + } + + @Test + void behavior() throws Exception { + FormatterStep step = PrinceOfSpaceStep.create(TestProvisioner.mavenCentral()); + String input = "class T { void m() { int x=1;} }"; + String formatted = format(step, input); + assertThat(formatted).contains("int x = 1;"); + assertThat(format(step, formatted)).isEqualTo(formatted); + } + + @Test + void behaviorWithOptions() throws Exception { + PrinceOfSpaceStep.Options options = new PrinceOfSpaceStep.Options(); + options.setIndentSize(2); + FormatterStep step = PrinceOfSpaceStep.create(PrinceOfSpaceStep.defaultVersion(), TestProvisioner.mavenCentral(), options); + String input = "class T { void m() { int x=1;} }"; + String formatted = format(step, input); + assertThat(formatted).contains("int x = 1;").contains("\n "); + assertThat(format(step, formatted)).isEqualTo(formatted); + } + + @Test + void equality() { + new SerializableEqualityTester() { + String version = PrinceOfSpaceStep.defaultVersion(); + Integer indentSize; + + @Override + protected void setupTest(API api) { + // same version == same + api.areDifferentThan(); + + // change the version, and it's different + version = "2.1.1"; + api.areDifferentThan(); + version = PrinceOfSpaceStep.defaultVersion(); + + // change the options, and it's different + indentSize = 4; + api.areDifferentThan(); + indentSize = null; + } + + @Override + protected FormatterStep create() { + PrinceOfSpaceStep.Options options; + if (indentSize == null) { + options = null; + } else { + options = new PrinceOfSpaceStep.Options(); + options.setIndentSize(indentSize); + } + return PrinceOfSpaceStep.create(version, TestProvisioner.mavenCentral(), options); + } + }.testEquals(); + } +} From a0a09ad9c34acc3e10de0c0a3cc2426a40b814db Mon Sep 17 00:00:00 2001 From: Andrew Gustafson <628811+agustafson@users.noreply.github.com> Date: Tue, 30 Jun 2026 17:05:26 +0000 Subject: [PATCH 2/3] Link CHANGES.md entries to PR #2991 --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-maven/CHANGES.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7a59cf101d..7a90d0f039 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space). +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space). ([#2991](https://github.com/diffplug/spotless/pull/2991)) ## [4.8.0] - 2026-06-29 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 6309b7eaa5..ace90863ab 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `princeOfSpace()` step. +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `princeOfSpace()` step. ([#2991](https://github.com/diffplug/spotless/pull/2991)) ## [8.8.0] - 2026-06-29 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index ac83692ad9..80b240eae7 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `` step. +- Add support for Java formatting via [`prince-of-space`](https://github.com/agustafson/prince-of-space) with the new `` step. ([#2991](https://github.com/diffplug/spotless/pull/2991)) ## [3.8.0] - 2026-06-29 ### Added From 7e9f655bad36fa90f647ab0f313a6172059d0770 Mon Sep 17 00:00:00 2001 From: Andrew Gustafson <628811+agustafson@users.noreply.github.com> Date: Tue, 30 Jun 2026 20:50:20 +0000 Subject: [PATCH 3/3] Update prince-of-space default version to 2.2.0 --- gradle/libs.versions.toml | 2 +- .../main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java | 2 +- plugin-gradle/README.md | 2 +- plugin-maven/README.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 60f3f847fb..675cd3fa3c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ 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" palantir-java-format = "com.palantir.javaformat:palantir-java-format:1.1.0" -prince-of-space-core = "io.github.agustafson.princeofspace:prince-of-space-core:2.1.2" +prince-of-space-core = "io.github.agustafson.princeofspace:prince-of-space-core:2.2.0" scalafmt-core = "org.scalameta:scalafmt-core_2.13:3.8.1" sortpom-sorter = "com.github.ekryd.sortpom:sortpom-sorter:4.0.0" tabletest-formatter-core = "org.tabletest:tabletest-formatter-core:1.1.1" diff --git a/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java b/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java index 49deb42225..f007a1dd52 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/PrinceOfSpaceStep.java @@ -34,7 +34,7 @@ public final class PrinceOfSpaceStep implements Serializable { private static final long serialVersionUID = 1L; private static final String NAME = "prince-of-space"; public static final String MAVEN_COORDINATE = "io.github.agustafson.princeofspace:prince-of-space-core:"; - public static final String DEFAULT_VERSION = "2.1.2"; + public static final String DEFAULT_VERSION = "2.2.0"; /** The jar that contains the formatter. */ private final JarState.Promised jarState; diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index c22a165d1f..6df48c4b32 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -320,7 +320,7 @@ spotless { java { princeOfSpace() // optional: configure any of the formatter's options - princeOfSpace('2.1.2') + princeOfSpace('2.2.0') .indentStyle('SPACES') // or 'TABS' .indentSize(4) .lineLength(120) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 22e057f9b7..47e9c885c0 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -299,7 +299,7 @@ any other maven phase (i.e. compile) then it can be configured as below; ```xml - 2.1.2 + 2.2.0 SPACES 4 120