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.