Java開発におけるErrorProneのススメ

こんにちは、今シーズンのNBAもGSWの試合は全試合観てる米林です🏀 今年は毎試合満員御礼のOracleアリーナに行って観戦したいなぁと思いつつカリフォルニア州オークランドの人たちはOracleがデータベースの会社って知ってるのかどうか毎回気になっています🏀

うちの会社ではJavaの開発において、Error Prone を積極的に取り入れている。 その理由はCTOのmopemopeが入れろって怖いから、ただそれだけである。

実際のところ導入して損は無いので皆さんも是非導入を検討して頂きたい。

Error Prone とは

github.com

Error Prone とはGoogleが公開していて、githubに記載されている説明のとおり “Catch common Java mistakes as compile-time errors” そのままである。 コンパイル時にエラーが起きそうなところははじいてしまおうという素敵なものだ。 Error Prone は Bazel, Maven, Ant, Gradle で動作します。

Java開発者の方に馴染みのある FindBugs のようなものだと思ってもらえると理解は早いと思います。

現在、私が開発しているプロジェクトでは Gradle に組み込んで IntelliJ から実行していて Error Prone のエラーをクリアしないと実行が出来ないため、エラーを直さないと CTO に怒られる以前に実行出来ないためエラーがある状態では業務に支障をきたしてしまいますので強制的にエラーは排除する必要があります😢

インストールなどは公式ドキュメントを見てください。イマドキのJavaの開発であれば、ほぼ Gradle プロジェクトで開発されていると思うので、Gradleに組み込んで実行するまでは3分もあれば確認出来るかと思います。私が自身で作ったプロジェクトに組み込んだ際には既存の build.gradle に以下を追加しただけです。

apply plugin: 'net.ltgt.errorprone'

repositories {
    mavenCentral()
}

configurations.errorprone {
    resolutionStrategy.force 'com.google.errorprone:error_prone_core:2.0.14'
}

bugpattern

バグパターンはエラーや警告などいくつかに分かれています。 こちらにバグパターンが一覧化されています。そこそこ数が多いですが、色々みていくと自身非常にためになったのでJava開発者の皆さんは是非みてみてください。

バグパターンは、それぞれのサンプル毎に Positive examplesNegative examples があります。英語って難しいですね、どっちが正しいのか最初理解に苦しみました。

バグパターンの一例ですが、ArrayToStringというものがあり、配列をそのまま toString している箇所はNGとなります。

githubexampleを置いておくのでcloneしてGradleでbuildしてみてください。エラーが以下のように表示されるので、Main.java を直しながら確認してみると分かりやすいと思います。

$ git clone https://github.com/yone098/error-prone-example.git
$ cd error-prone-example/
$ gradle clean run
:clean
:compileJava
/Users/yone098/p/error-prone-example/src/main/java/example/Main.java:17: エラー: [ArrayToString] Calling toString on an array does not provide useful information
        System.out.println(nameArray);
                           ^
    (see http://errorprone.info/bugpattern/ArrayToString)
  Did you mean 'System.out.println(Arrays.toString(nameArray));'?
エラー1:compileJava FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed with exit code 1; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 5.081 secs

custom plugin

plugin としてカスタムチェックを追加することが可能です。 BugCheckerを継承して、MethodInvocationTreeMatcherを実装しプラグインを作成します。

@AutoService(BugChecker.class) // the service descriptor
@BugPattern(
  name = "MyCustomCheck",
  // ...
)
public class MyCustomCheck extends BugChecker implements MethodInvocationTreeMatcher {
  @Override
  public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    // TODO:
  }
}

Gradleで利用するには

configurations {
  annotationProcessor
}

dependencies {
  annotationProcessor project(':custom-checks')
}

tasks.withType(JavaCompile) {
  options.compilerArgs += [ '-processorpath', configurations.annotationProcessor.asPath ]
}

詳しくは、Plugin Checksをチェックしてください。

最後に

Java開発している方には是非、自身のプログラムを ErrorProne で一度チェックしてみては如何でしょうか?

そして、株式会社Abbyでは絶賛開発者を募集しています。現在、募集しているプロジェクトでは CTO のもとで一緒に楽しく開発出来ますし、もちろん一緒に ErrorProne も見守ってくれます。

気軽にtwitterFacebookなどで声かけてください。そして一度弊社まで遊びにきてください!よろしくお願いします!