diff --git a/CHANGES.md b/CHANGES.md
index 5b0e8c042a..7a90d0f039 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). ([#2991](https://github.com/diffplug/spotless/pull/2991))
## [4.8.0] - 2026-06-29
### Added
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b8807b1dd4..675cd3fa3c 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.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/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..f007a1dd52
--- /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.2.0";
+
+ /** 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..ace90863ab 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. ([#2991](https://github.com/diffplug/spotless/pull/2991))
## [8.8.0] - 2026-06-29
### Added
diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index 443acf7851..6df48c4b32 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.2.0')
+ .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..80b240eae7 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. ([#2991](https://github.com/diffplug/spotless/pull/2991))
## [3.8.0] - 2026-06-29
### Added
diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index 1d0bf6d25f..47e9c885c0 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.2.0
+ 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();
+ }
+}