Skip to content

How to beautify java code reliably

March 09, 2022Jérémie Chauvel4 min read

Readable and formatted code

I recently had to set up code formatting on a spring boot java application. Auto code formatting is important to avoiding useless diffs in source files, reducing noise in code review, allowing reviewers to focus on what matters.

Ideally we want:

  • Automatic formatting on file save in IDE's (vscode, IntelliJ)
  • Capacity to run in CI

I wanted to integrate well with vscode and after trying some solution like:

  • java autoformat, which I couldn't run in CI and that was not really portable between IDEs
  • maven auto formatting plugin (didn't run on save easily in IDEs)

I ended up, from a friend suggestion, looking into a java prettier plugin. Prettier allowed for an easy integration with most Web IDE, can be configured to format on save for vscode and is trivial to run in CI.

Installing prettier for java

Let's start with the setup in command line:

{
  "name": "api",
  "version": "0.0.1",
  "private": true,
  "devDependencies": {
    "prettier": "2.5.1",
    "prettier-plugin-java": "1.6.1"
  },
  "engines": {
    "node": "16.x"
  },
  "scripts": {
    "format": "prettier --write \"{,**/}*.{java,yml,yaml,md,json}\"",
    "check-format": "prettier --check \"{,**/}*.{java,yml,yaml,md,json}\"",
    "lint": "npm run check-format"
  }
}
  • Install the required node_module: npm install

💡 Don't forget to add node_modules to your .gitignore.

💡 I highly recommend adding a .prettierignore that list autogenerated files to avoid formatting those, eg:

node_modules
target

You can now format java code running npm run format 🚀

💡 Do not forget to add node as a dependency for your project installation and to run npm ci in your project installation script for new developers.

We now want to improve developer experience by integrating with IDEs, running the formatter in CLI being impractical.

Monorepo

If you are using a monorepo, I highly recommend setting up prettier in the root of your monorepo instead of setting up prettier in each sub directory.

Integrating with IDEs

vscode

To set up prettier in vscode: add the prettier for java extension to recommended vscode extensions for the project, to do so, you can simply add the id of the extension to: .vscode/extensions.json:

{
  "recommendations": [
	"pivotal.vscode-boot-dev-pack",
	"vscjava.vscode-java-pack",
	"redhat.vscode-xml",
	"sonarsource.sonarlint-vscode",
	"gabrielbb.vscode-lombok",
	"dbaeumer.vscode-eslint",
+	"esbenp.prettier-vscode", // the classic prettier extension
	"shengchen.vscode-checkstyle",
  ]
}

then set up this extension as the default linter for java file in .vscode/settings.json :

{
// rest of your configuration
// automatic format on save, I recommend the save on focus lost option as well
+	"editor.formatOnSave": true,
+	"[java]": {
+		"editor.defaultFormatter": "esbenp.prettier-vscode"
+	}
}

Already we can easily format java code on save: Formatting java code on save

I highly recommend checking in the .vscode folder in your versioning tool (most likely git) to share this configuration with all developers.

IntelliJ

To integrate with prettier java formatter:

Name: Prettier-java
File type: Java
Program:  full path to `.bin/prettier` eg: `node_modules/.bin/prettier`
Arguments: --write $FilePathRelativeToProjectRoot$
Output paths to refresh: $FilePathRelativeToProjectRoot
Auto-save edited files to trigger the watcher: check it
Trigger the watcher on external changes: check it

prettier documentation can be found here for IntelliJ integration

Integrate code formatting check in CI

Now we only need to integrate this check in CI, I'm using gitlab for this example, but the principles can be transposed to any other CI.

First we need to add a new job:

stages:
  - build
  - test
  - deploy

# ... rest of the file

# beautify backend files with prettier
lint-back:
  image: node:lts-alpine # We use a node image to run prettier
  stage: test # must match an existing stage
  needs: [] # none required optimization that explain to gitlab ci that this test has no dependency and can start as soon as possible
  script:
    - npm ci
    - npm run lint
# ... rest of the file

now just push your change, and you are all set:

CI running lint successfully

Jérémie Chauvel

Jérémie Chauvel

Tech Lead @ Theodo