diff --git a/CHANGES.md b/CHANGES.md
index 87d919a7d6..7d9f8ba0f9 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 `tabletest-formatter` support for Java and Kotlin. ([#2860](https://github.com/diffplug/spotless/pull/2860))
### Fixed
- Fix the ability to specify a wildcard version (`*`) for external formatter executables, which did not work. ([#2848](https://github.com/diffplug/spotless/pull/2848))
diff --git a/lib/build.gradle b/lib/build.gradle
index 98a511a381..38d1c3de3c 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -24,6 +24,7 @@ def NEEDS_GLUE = [
'palantirJavaFormat',
'scalafmt',
'sortPom',
+ 'tableTestFormatter',
'zjsonPatch',
]
for (glue in NEEDS_GLUE) {
@@ -122,6 +123,8 @@ dependencies {
// sortPom
sortPomCompileOnly 'com.github.ekryd.sortpom:sortpom-sorter:4.0.0'
sortPomCompileOnly 'org.slf4j:slf4j-api:2.0.17'
+ // tableTestFormatter
+ tableTestFormatterCompileOnly 'org.tabletest:tabletest-formatter-core:1.0.1'
// zjsonPatch
zjsonPatchCompileOnly 'com.flipkart.zjsonpatch:zjsonpatch:0.4.16'
}
diff --git a/lib/src/main/java/com/diffplug/spotless/java/TableTestFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/java/TableTestFormatterStep.java
new file mode 100644
index 0000000000..b55f0a9405
--- /dev/null
+++ b/lib/src/main/java/com/diffplug/spotless/java/TableTestFormatterStep.java
@@ -0,0 +1,90 @@
+/*
+ * 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 com.diffplug.spotless.FormatterFunc;
+import com.diffplug.spotless.FormatterStep;
+import com.diffplug.spotless.JarState;
+import com.diffplug.spotless.Provisioner;
+
+/**
+ * Formats {@code @TableTest} annotation tables in Java and Kotlin source files.
+ * Configuration is read from {@code .editorconfig} files.
+ */
+public final class TableTestFormatterStep implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ private static final String NAME = "tableTestFormatter";
+ private static final String MAVEN_COORDINATE = "org.tabletest:tabletest-formatter-core:";
+ private static final String DEFAULT_VERSION = "1.0.1";
+
+ private final JarState.Promised jarState;
+ private final String version;
+
+ private TableTestFormatterStep(JarState.Promised jarState, String version) {
+ this.jarState = jarState;
+ this.version = version;
+ }
+
+ /** Creates a step which formats {@code @TableTest} tables using the default version. */
+ public static FormatterStep create(Provisioner provisioner) {
+ return create(defaultVersion(), provisioner);
+ }
+
+ /** Creates a step which formats {@code @TableTest} tables using the given version. */
+ public static FormatterStep create(String version, Provisioner provisioner) {
+ Objects.requireNonNull(version, "version");
+ Objects.requireNonNull(provisioner, "provisioner");
+ return FormatterStep.create(NAME,
+ new TableTestFormatterStep(JarState.promise(() -> JarState.from(MAVEN_COORDINATE + version, provisioner)), version),
+ TableTestFormatterStep::equalityState,
+ State::createFormat);
+ }
+
+ /** Get default formatter version. */
+ public static String defaultVersion() {
+ return DEFAULT_VERSION;
+ }
+
+ private State equalityState() {
+ return new State(jarState.get(), version);
+ }
+
+ private static final class State implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ private final JarState jarState;
+ private final String version;
+
+ State(JarState jarState, String version) {
+ this.jarState = jarState;
+ this.version = version;
+ }
+
+ FormatterFunc createFormat() throws Exception {
+ ClassLoader classLoader = jarState.getClassLoader();
+ Class> formatterClazz = classLoader.loadClass("com.diffplug.spotless.glue.java.TableTestFormatterFunc");
+ Constructor> constructor = formatterClazz.getConstructor();
+ return (FormatterFunc.NeedsFile) constructor.newInstance();
+ }
+ }
+}
diff --git a/lib/src/tableTestFormatter/java/com/diffplug/spotless/glue/java/TableTestFormatterFunc.java b/lib/src/tableTestFormatter/java/com/diffplug/spotless/glue/java/TableTestFormatterFunc.java
new file mode 100644
index 0000000000..06c08ae100
--- /dev/null
+++ b/lib/src/tableTestFormatter/java/com/diffplug/spotless/glue/java/TableTestFormatterFunc.java
@@ -0,0 +1,49 @@
+/*
+ * 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.java;
+
+import java.io.File;
+
+import org.tabletest.formatter.config.Config;
+import org.tabletest.formatter.config.EditorConfigProvider;
+import org.tabletest.formatter.core.SourceFileFormatter;
+import org.tabletest.formatter.core.TableTestFormatter;
+
+import com.diffplug.spotless.FormatterFunc;
+
+/**
+ * Formats {@code @TableTest} annotation tables in Java and Kotlin source files.
+ */
+public class TableTestFormatterFunc implements FormatterFunc.NeedsFile {
+
+ private static final EditorConfigProvider CONFIG_PROVIDER = new EditorConfigProvider();
+
+ private final TableTestFormatter tableFormatter = new TableTestFormatter();
+ private final SourceFileFormatter sourceFormatter = new SourceFileFormatter();
+
+ @Override
+ public String applyWithFile(String unix, File file) throws Exception {
+ String fileName = file.getName();
+
+ if (fileName.endsWith(".java") || fileName.endsWith(".kt")) {
+ Config config = CONFIG_PROVIDER.lookupConfig(file.toPath(), Config.SPACES_4);
+ String formatted = sourceFormatter.format(unix, config);
+ return formatted.equals(unix) ? unix : formatted;
+ }
+
+ return unix;
+ }
+}
diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md
index b73e607579..5d8394f5df 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 `tabletest-formatter` support for Java and Kotlin. ([#2860](https://github.com/diffplug/spotless/pull/2860))
### Fixed
- Fix the ability to specify a wildcard version (`*`) for external formatter executables, which did not work. ([#2848](https://github.com/diffplug/spotless/pull/2848))
diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index d07316069b..c41f6eec31 100644
--- a/plugin-gradle/README.md
+++ b/plugin-gradle/README.md
@@ -56,9 +56,9 @@ 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), [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), [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), [prettier](#prettier))
+ - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [tabletest-formatter](#tabletest-formatter-1), [prettier](#prettier))
- [Scala](#scala) ([scalafmt](#scalafmt))
- [C/C++](#cc) ([clang-format](#clang-format), [eclipse cdt](#eclipse-cdt))
- [Protobuf](#protobuf) ([buf](#buf), [clang-format](#clang-format))
@@ -220,6 +220,8 @@ spotless {
clangFormat() // has its own section below
idea() // has its own section below
+ tableTestFormatter() // has its own section below
+
formatAnnotations() // fixes formatting of type annotations, see below
licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile
@@ -428,6 +430,17 @@ spotless {
.includeDraft(false) // You may exclude draft mutators (from Composite ones)
```
+### tabletest-formatter
+
+[homepage](https://github.com/nchaugen/tabletest-formatter). [changelog](https://github.com/nchaugen/tabletest-formatter/releases). Formats [`@TableTest`](https://github.com/nchaugen/tabletest) tables in Java source files. All configuration is read from `.editorconfig` files.
+
+```gradle
+spotless {
+ java {
+ tableTestFormatter()
+ // optional: you can specify a specific version
+ tableTestFormatter('1.0.1')
+```
@@ -510,6 +523,7 @@ spotless { // if you are using build.gradle.kts, instead of 'spotless {' use:
ktlint() // has its own section below
diktat() // has its own section below
prettier() // has its own section below
+ tableTestFormatter() // has its own section below
licenseHeader '/* (C)$YEAR */' // or licenseHeaderFile
}
kotlinGradle {
@@ -593,6 +607,18 @@ spotless {
diktat('1.0.1').configFile("full/path/to/diktat-analysis.yml")
```
+### tabletest-formatter
+
+[homepage](https://github.com/nchaugen/tabletest-formatter). [changelog](https://github.com/nchaugen/tabletest-formatter/releases). Formats [`@TableTest`](https://github.com/nchaugen/tabletest) tables in Kotlin source files. All configuration is read from `.editorconfig` files.
+
+```kotlin
+spotless {
+ kotlin {
+ tableTestFormatter()
+ // optional: you can specify a specific version
+ tableTestFormatter('1.0.1')
+```
+
## Scala
diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
index 975be992c2..a067ddbbef 100644
--- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
+++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/BaseKotlinExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2025 DiffPlug
+ * Copyright 2023-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
import com.diffplug.common.collect.ImmutableSortedMap;
import com.diffplug.spotless.FileSignature;
import com.diffplug.spotless.FormatterStep;
+import com.diffplug.spotless.java.TableTestFormatterStep;
import com.diffplug.spotless.kotlin.DiktatStep;
import com.diffplug.spotless.kotlin.KtLintStep;
import com.diffplug.spotless.kotlin.KtfmtStep;
@@ -69,6 +70,30 @@ public KtfmtConfig ktfmt(String version) {
return new KtfmtConfig(version);
}
+ /** Formats {@code @TableTest} annotation tables using tabletest-formatter. */
+ public TableTestFormatterConfig tableTestFormatter() {
+ return tableTestFormatter(TableTestFormatterStep.defaultVersion());
+ }
+
+ /** Formats {@code @TableTest} annotation tables using the given version of tabletest-formatter. */
+ public TableTestFormatterConfig tableTestFormatter(String version) {
+ Objects.requireNonNull(version);
+ return new TableTestFormatterConfig(version);
+ }
+
+ public final class TableTestFormatterConfig {
+ final String version;
+
+ TableTestFormatterConfig(String version) {
+ this.version = Objects.requireNonNull(version);
+ addStep(createStep());
+ }
+
+ private FormatterStep createStep() {
+ return TableTestFormatterStep.create(version, provisioner());
+ }
+ }
+
protected abstract boolean isScript();
public final class DiktatConfig {
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 7ae0fe90ee..90684b323d 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
@@ -47,6 +47,7 @@
import com.diffplug.spotless.java.ImportOrderStep;
import com.diffplug.spotless.java.PalantirJavaFormatStep;
import com.diffplug.spotless.java.RemoveUnusedImportsStep;
+import com.diffplug.spotless.java.TableTestFormatterStep;
public class JavaExtension extends FormatExtension implements HasBuiltinDelimiterForLicense, JvmLang {
static final String NAME = "java";
@@ -507,6 +508,30 @@ private FormatterStep createStep() {
}
}
+ /** Formats {@code @TableTest} annotation tables using tabletest-formatter. */
+ public TableTestFormatterConfig tableTestFormatter() {
+ return tableTestFormatter(TableTestFormatterStep.defaultVersion());
+ }
+
+ /** Formats {@code @TableTest} annotation tables using tabletest-formatter. */
+ public TableTestFormatterConfig tableTestFormatter(String version) {
+ Objects.requireNonNull(version);
+ return new TableTestFormatterConfig(version);
+ }
+
+ public class TableTestFormatterConfig {
+ final String version;
+
+ TableTestFormatterConfig(String version) {
+ this.version = Objects.requireNonNull(version);
+ addStep(createStep());
+ }
+
+ private FormatterStep createStep() {
+ return TableTestFormatterStep.create(version, provisioner());
+ }
+ }
+
/** If the user hasn't specified the files yet, we'll assume he/she means all of the java files. */
@Override
protected void setupTask(SpotlessTask task) {
diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md
index adc8341618..49aa472432 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 `tabletest-formatter` support for Java and Kotlin. ([#2860](https://github.com/diffplug/spotless/pull/2860))
### Fixed
- Fix the ability to specify a wildcard version (`*`) for external formatter executables, which did not work. ([#2848](https://github.com/diffplug/spotless/pull/2848))
diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index 16fbab9f76..98714d452d 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -40,9 +40,9 @@ 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), [IntelliJ IDEA](#intellij-idea))
+ - [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))
- [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy))
- - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier))
+ - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [tabletest-formatter](#tabletest-formatter-1), [prettier](#prettier))
- [Scala](#scala) ([scalafmt](#scalafmt))
- [C/C++](#cc) ([eclipse cdt](#eclipse-cdt), [clang-format](#clang-format))
- [Python](#python) ([black](#black))
@@ -216,6 +216,8 @@ any other maven phase (i.e. compile) then it can be configured as below;
+
+
false
@@ -399,6 +401,16 @@ These mechanisms already exist for the Gradle plugin.
```
+### tabletest-formatter
+
+[homepage](https://github.com/nchaugen/tabletest-formatter). [changelog](https://github.com/nchaugen/tabletest-formatter/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TableTestFormatter.java). Formats [`@TableTest`](https://github.com/nchaugen/tabletest) tables in Java source files. All configuration is read from `.editorconfig` files.
+
+```xml
+
+ 1.0.1
+
+```
+
## Groovy
[code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy/Groovy.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy).
@@ -462,6 +474,8 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T
+
+
/* (C)$YEAR */
@@ -523,6 +537,16 @@ Additionally, `editorConfigOverride` options will override what's supplied in `.
```
+### tabletest-formatter
+
+[homepage](https://github.com/nchaugen/tabletest-formatter). [changelog](https://github.com/nchaugen/tabletest-formatter/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/TableTestFormatter.java). Formats [`@TableTest`](https://github.com/nchaugen/tabletest) tables in Kotlin source files. All configuration is read from `.editorconfig` files.
+
+```xml
+
+ 1.0.1
+
+```
+
## Scala
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 acc97647d7..30616bfdb4 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
@@ -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.
@@ -92,6 +92,10 @@ public void addCleanthat(CleanthatJava cleanthat) {
addStepFactory(cleanthat);
}
+ public void addTableTestFormatter(TableTestFormatter tableTestFormatter) {
+ addStepFactory(tableTestFormatter);
+ }
+
private static String fileMask(Path path) {
String dir = path.toString();
if (!dir.endsWith(File.separator)) {
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TableTestFormatter.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TableTestFormatter.java
new file mode 100644
index 0000000000..2b76fbb080
--- /dev/null
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TableTestFormatter.java
@@ -0,0 +1,38 @@
+/*
+ * 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.TableTestFormatterStep;
+import com.diffplug.spotless.maven.FormatterStepConfig;
+import com.diffplug.spotless.maven.FormatterStepFactory;
+
+/**
+ * Formats {@code @TableTest} annotation tables. Configuration is read from {@code .editorconfig} files.
+ */
+public class TableTestFormatter implements FormatterStepFactory {
+
+ @Parameter
+ private String version;
+
+ @Override
+ public FormatterStep newFormatterStep(FormatterStepConfig config) {
+ String version = this.version != null ? this.version : TableTestFormatterStep.defaultVersion();
+ return TableTestFormatterStep.create(version, config.getProvisioner());
+ }
+}
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
index 18eb13773d..5b4e0a3f20 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2023 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.
@@ -49,4 +49,8 @@ public void addKtfmt(Ktfmt ktfmt) {
public void addDiktat(Diktat diktat) {
addStepFactory(diktat);
}
+
+ public void addTableTestFormatter(TableTestFormatter tableTestFormatter) {
+ addStepFactory(tableTestFormatter);
+ }
}
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/TableTestFormatter.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/TableTestFormatter.java
new file mode 100644
index 0000000000..4702f605da
--- /dev/null
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/TableTestFormatter.java
@@ -0,0 +1,38 @@
+/*
+ * 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.kotlin;
+
+import org.apache.maven.plugins.annotations.Parameter;
+
+import com.diffplug.spotless.FormatterStep;
+import com.diffplug.spotless.java.TableTestFormatterStep;
+import com.diffplug.spotless.maven.FormatterStepConfig;
+import com.diffplug.spotless.maven.FormatterStepFactory;
+
+/**
+ * Formats {@code @TableTest} annotation tables. Configuration is read from {@code .editorconfig} files.
+ */
+public class TableTestFormatter implements FormatterStepFactory {
+
+ @Parameter
+ private String version;
+
+ @Override
+ public FormatterStep newFormatterStep(FormatterStepConfig config) {
+ String version = this.version != null ? this.version : TableTestFormatterStep.defaultVersion();
+ return TableTestFormatterStep.create(version, config.getProvisioner());
+ }
+}
diff --git a/testlib/src/main/resources/java/tableTestFormatter/JavaCodeFormatted.test b/testlib/src/main/resources/java/tableTestFormatter/JavaCodeFormatted.test
new file mode 100644
index 0000000000..13ee64eb9b
--- /dev/null
+++ b/testlib/src/main/resources/java/tableTestFormatter/JavaCodeFormatted.test
@@ -0,0 +1,13 @@
+import org.tabletest.junit.TableTest;
+
+class CalculatorTest {
+
+ @TableTest("""
+ scenario | a | b | sum?
+ positive | 1 | 2 | 3
+ negative | -1 | -2 | -3
+ """)
+ void shouldAddNumbers(int a, int b, int sum) {
+ assert a + b == sum;
+ }
+}
diff --git a/testlib/src/main/resources/java/tableTestFormatter/JavaCodeUnformatted.test b/testlib/src/main/resources/java/tableTestFormatter/JavaCodeUnformatted.test
new file mode 100644
index 0000000000..73ae7f074a
--- /dev/null
+++ b/testlib/src/main/resources/java/tableTestFormatter/JavaCodeUnformatted.test
@@ -0,0 +1,13 @@
+import org.tabletest.junit.TableTest;
+
+class CalculatorTest {
+
+ @TableTest("""
+ scenario | a | b | sum?
+ positive|1|2|3
+ negative| -1 | -2 | -3
+ """)
+ void shouldAddNumbers(int a, int b, int sum) {
+ assert a + b == sum;
+ }
+}
diff --git a/testlib/src/test/java/com/diffplug/spotless/java/TableTestFormatterStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/TableTestFormatterStepTest.java
new file mode 100644
index 0000000000..6c72eb007f
--- /dev/null
+++ b/testlib/src/test/java/com/diffplug/spotless/java/TableTestFormatterStepTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.junit.jupiter.api.Test;
+
+import com.diffplug.spotless.FormatterStep;
+import com.diffplug.spotless.ResourceHarness;
+import com.diffplug.spotless.SerializableEqualityTester;
+import com.diffplug.spotless.StepHarnessWithFile;
+import com.diffplug.spotless.TestProvisioner;
+
+class TableTestFormatterStepTest extends ResourceHarness {
+
+ private static final String VERSION = "1.0.1";
+
+ @Test
+ void behavior() {
+ FormatterStep step = TableTestFormatterStep.create(VERSION, TestProvisioner.mavenCentral());
+ try (StepHarnessWithFile harness = StepHarnessWithFile.forStep(this, step)) {
+ harness.testResource("CalculatorTest.java", "java/tableTestFormatter/JavaCodeUnformatted.test", "java/tableTestFormatter/JavaCodeFormatted.test");
+ }
+ }
+
+ @Test
+ void equality() {
+ new SerializableEqualityTester() {
+ String version = VERSION;
+
+ @Override
+ protected void setupTest(API api) {
+ // same version == same
+ api.areDifferentThan();
+
+ // change the version, and it's different
+ version = "1.0.0";
+ api.areDifferentThan();
+ }
+
+ @Override
+ protected FormatterStep create() {
+ return TableTestFormatterStep.create(version, TestProvisioner.mavenCentral());
+ }
+ }.testEquals();
+ }
+}