To main content

There might be a decent code formatter for Java after all!

Published by Benjamin Marwell on

Why are there no decent code formatters for Java? – a great question asked by Jan Ouwens one year ago. I found myself asking the same question after palantir-java-format stopped working for me.

Introducing jdtfmt

By combining just a few components:

  • PicoCLI as a command line parser

  • GraalVM to build a native image

  • Eclipse JDT as the primary code formatter

  • A default configuration file

… and we have a new tool: jdtfmt!

jdtfmt: A command line formatter for Java

jdtfmt has the same design goal as, let’s say, gofmt for go: Define a simple CLI tool which formats files in a generally accepted default layout.

The project is in early stages, but the CI can already output binaries for Mac aarch64, Mac x64, Linux x64 and Windows x64. We are still in a discussion phase. Feel free to join our discussions for jdtfmt. Or raise issues or pull requests.

Oh, and let me know what you think of this idea!

Palantir’s formatting issues

The reason why I built this tool: As of July 2025, palantir-java-format was not able to format text blocks properly. An issue now two years old, and nowhere near to be fixed.

Other problems included:

  • No support for unnamed variables (_).

  • No good formatting of switch expressions.

Eclipse JDT as an intermediate solution

After some web research, I found Jan’s blog post and that he switched to Eclipse JDT as his default formatter. Although Eclipse JDT is highly configurable, it lacks a straightforward command-line tool. However, as a user of mcs, I know that native binaries can be built using GraalVM.

So, there was an obvious thing to do…​

Usage of jdtfmt

The commands are: jdtfmt write, jdtfmt list and jdtfmt diff.

❯ jdtfmt list --all .
Processing file: ./cli/src/main/java/io/github/bmarwell/jdtfmt/nio/PathUtils.java
Processing file: ./cli/src/test/resources/diff/SomeRecord.java
Not formatted correctly: ./cli/src/test/resources/diff/SomeRecord.java
Processing file: ./integration-tests/jreleaser-builtin/src/test/resources/correctly_formatted/CorrectlyFormatted.java
Processing file: ./integration-tests/jreleaser-builtin/src/test/resources/incorrectly_formatted/SomeRecord.java
Not formatted correctly: ./integration-tests/jreleaser-builtin/src/test/resources/incorrectly_formatted/SomeRecord.java
Processing file: ./integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jdtfmt/its/jreleaser/builtin/WriteCommandIT.java
Processing file: ./cli/src/test/java/io/github/bmarwell/jdtfmt/JdtFmtTest.java
Processing file: ./integration-tests/jreleaser-builtin/src/test/resources/write/t001/SomeRecord.java
Not formatted correctly: ./integration-tests/jreleaser-builtin/src/test/resources/write/t001/SomeRecord.java
[...]

It is fast: The command only takes 0.02s, while the Java execution takes 2.3s.