Linting Java Projects

This page will discuss common topics around enforcing the code quality of Java codebases using the Mill build tool

ErrorProne

When adding the ErrorPromeModule to your JavaModule, the error-prone compiler plugin automatically detects various kind of programming errors.

build.mill (download, browse)
package build
import mill._, javalib._
import mill.contrib.errorprone._

import $ivy.`com.lihaoyi::mill-contrib-errorprone:`

object `package` extends RootModule with JavaModule with ErrorProneModule {
  def errorProneOptions = Seq("-XepAllErrorsAsWarnings")
}
src/example/ShortSet.java (browse)
package example;

import java.util.HashSet;
import java.util.Set;

public class ShortSet {
  public static void main (String[] args) {
    Set<Short> s = new HashSet<>();
    for (short i = 0; i < 100; i++) {
      s.add(i);
      s.remove(i - 1);
    }
    System.out.println(s.size());
  }
}
> ./mill show errorProneOptions
[
  "-XepAllErrorsAsWarnings"
]

> ./mill compile
[warn] .../src/example/ShortSet.java:11:15:  [CollectionIncompatibleType] Argument 'i - 1' should not be passed to this method; its type int is not compatible with its collection's type argument Short
[warn]       s.remove(i - 1);
[warn]               ^    (see https://errorprone.info/bugpattern/CollectionIncompatibleType)
[warn] 1 warning
[warn]               ^

Find more details on the ErrorProne plugin page.

Checkstyle

build.mill (download, browse)
package build
import mill._, javalib._
import $ivy.`com.lihaoyi::mill-contrib-checkstyle:`

import mill.contrib.checkstyle._

object `package` extends RootModule with CheckstyleModule {
  def checkstyleVersion = "9.3"
}
> ./mill checkstyle # run checkstyle to produce a report, defaults to warning without error
...src/InputWhitespaceCharacters.java:3:23: Line contains a tab character...
...src/InputWhitespaceCharacters.java:16:3: Line contains a tab character...
...src/InputFileName1.java:2:1: Top-level class MyAnnotation1 has to reside in its own source file...
...src/InputFileName1.java:13:1: Top-level class Enum1 has to reside in its own source file...
...src/InputFileName1.java:26:1: Top-level class TestRequireThisEnum has to reside in its own source file...
Audit done.

> sed -i.bak 's/warning/error/g' checkstyle-config.xml # make checkstyle error on violations

> ./mill checkstyle
error: ...src/InputWhitespaceCharacters.java:3:23: Line contains a tab character...
...src/InputWhitespaceCharacters.java:16:3: Line contains a tab character...
...src/InputFileName1.java:2:1: Top-level class MyAnnotation1 has to reside in its own source file...
...src/InputFileName1.java:13:1: Top-level class Enum1 has to reside in its own source file...
...src/InputFileName1.java:26:1: Top-level class TestRequireThisEnum has to reside in its own source file...
Audit done.

> sed -i.bak 's/\t/    /g' src/InputWhitespaceCharacters.java

> rm src/InputFileName1.java

> ./mill checkstyle # after fixing the violations, checkstyle no longer errors
Audit done.

Jacoco Code Coverage

Mill supports Java code coverage analysis via the mill-jacoco plugin. See the plugin repository documentation for more details: