Enforcing formatting standards for your Java project using Gradle

Anirudh Ramesh
4 min readOct 8, 2021

--

AKA how your team can remain sane during code reviews:

https://xkcd.com/1513/

Before I begin, let me cover all the ways you can do this. If. you want to get straight to the content, you can go to the “How do I do this in Gradle” section.

Easy but sub-optimal way: Use .editorconf file

You can setup an .editorconf — which is supported by most text editors. However, it is VERY easy to override. Not enforcible — at all! Also, each person can easily have editor-specific styles, which makes this completely redundant.

Prettier + Pretty-Quick + Husky

If you are willing to go the node/npm route — there are plenty of great options available! My personal favorite is prettier (linting tool) + pretty-quick (only runs prettier on staged files) + husky (runs whatever command you please using git-hooks 🤩). What is more — prettier picks up editorconf properties automatically and overrides properties that clash.

Extremely easy to set up: https://prettier.io/docs/en/precommit.html .

However, would you really want to introduce package.json , a lock file, node modules into an already giant java codebase? Yeah, I didn’t think so.

But, but, what if I use maven?

Good for you. There is a prettier maven plugin. Don’t like prettier ? There are million other plugins in maven which do the job for you.

Also, there is aprecommit plugin. You can use this to make sure your code is always linted before it is committed 😉. It should be extremely straightforward to implement this.

Now, Coming back to the topic at hand:

How do I do this in gradle:

  1. Choose a gradle plugin, I am using spotless for this example, anything else should work just as well.
  2. Add it to your plugins :
plugins {
id 'org.springframework.boot' version '2.4.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
id 'java'
id 'jacoco'
id "com.diffplug.spotless" version "5.16.0"
} // Note this is not the legacy way of adding plugins in gradle (for older versions), if you want to do that, check this out - https://plugins.gradle.org/plugin/com.diffplug.spotless

3. Setup your Linter task. For spotless , it is:

spotless {
// optional: limit format enforcement to just the files changed by this feature branch
// ratchetFrom 'origin/main'

format 'misc', {
// define the files to apply `misc` to
target '*.gradle', '*.md', '.gitignore'

// define the steps to apply to those files
trimTrailingWhitespace()
indentWithSpaces(3) // or spaces. Takes an integer argument if you don't like 4
endWithNewline()
setEncoding('utf-8')
}
java {
eclipse() // I like eclipse formatting over google
// googleJavaFormat('1.11.0').aosp().reflowLongStrings(), this is the other option
}
}

Note: Initially, comment out ratchetFrom property. This property is used to do incremental linting. i.e — Compare what is in your main / masterbranch and only do linting on changed files (saves time ⏱). For now, leave it commented.

4. Time to commit your build.gradle file

5. run ./gradlew spotlessApply . This will lint all of your files. Commit them (or whatever task your linter provides).

6. Now you can uncomment ratchetFrom property and commit this change.

Now, it is time for you to make this run automatically on every commit:

Note: Thanks to https://gist.github.com/KenVanHoeylandt/c7a928426bce83ffab400ab1fd99054a (I’ve modified this quite a bit).

Step 1: Create a install-git-hooks.gradle file in any path you please. I keep it at the project root-directory.

These are the contents of it:

task installGitHooks(type: Copy) {
println '================================================'
println 'I am installing commit-msg Git hook in .git/hooks - hang tight!'
println '================================================'
from new File(rootProject.rootDir, 'commit-msg')
into { new File(rootProject.rootDir, '.git/hooks') }
}

test.dependsOn installGitHooks

Step 2: Create a file commit-msg which will be the hook that is fired when you do git commit .

#!/bin/sh

echo "======================================================================"
echo "BEEP BOP, I AM COMMIT-MSG.SH, I am going to run SPOTLESS on your code now!"
echo "I use Eclipse-JDI linting, If you don't like it, you can use others (Google Java formatting?)"
echo "refer to build.gradle and change the spotless plugin if you want to change how I work!"
echo "======================================================================"

./gradlew spotlessApply

git add .

echo "======================================================================"
echo "I have run spotless, your code is L I N T E D. I am commiting your new code"
echo "======================================================================"

Step 3: Apply this plugin to your build.gradle :

plugins {
id 'org.springframework.boot' version '2.4.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
id 'java'
id 'jacoco'
id "com.diffplug.spotless" version "5.16.0"
}

group = 'com.example.project'
sourceCompatibility = '11'

apply from: rootProject.file('install-git-hooks.gradle')

Step 4: run ./gradlew test once. If you run this once, this hook is set up for good!

Step 5: Sit back and enjoy the linting 🍻. Your code will be linted before it is committed.

--

--