以下の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/06/15/230411より取得しました。


GoogleのJavaの静的解析ツール、Error Proneを試す

これは、なにをしたくて書いたもの?

Javaの静的解析ツールといえばSpotBugs、PMD、CheckStyleあたりが有名ですが、Error Proneというものも試してみようかなと
ということで。

Error Prone

Error Proneは、Googleが開発しているJavaの静的解析ツールです。

Error Prone

GitHubリポジトリーはこちら。

GitHub - google/error-prone: Catch common Java mistakes as compile-time errors

Error Proneがどういうものかは、インストールドキュメントを見ると書かれています。

Installation

Javaコンパイル時にチェックを追加するもののようです。

Our goal is to make it simple to add Error Prone checks to your existing Java compilation.

実際、ドキュメントを見るとjavacコマンドのプラグインおよびPluggable Annotation Processing APIを使って動作するものに
なっています。

ところで、javacコマンドにプラグインの機構があることを知りませんでした…。

javacコマンド

Plugin (Java SE 21 & JDK 21)

Error Proneを使うには、Java 17以降が必要になるようです。

Please note that Error Prone must be run on JDK 17 or newer.

検出可能なバグパターンはこちら。

Bug Patterns

実験用とされているもの以外は、デフォルトですべて有効なようですね。

また自分でルールを追加することもできるようです。

Plugin checks

今回は単純にセットアップして、GitHubリポジトリーのREADME.mdに記載されている簡単なサンプルを動かすくらいに
しておきたいと思います。使うビルドツールは、Apache Mavenとします。

環境

今回の環境はこちら。

$ java --version
openjdk 21.0.7 2025-04-15
OpenJDK Runtime Environment (build 21.0.7+6-Ubuntu-0ubuntu124.04)
OpenJDK 64-Bit Server VM (build 21.0.7+6-Ubuntu-0ubuntu124.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.10 (5f519b97e944483d878815739f519b2eade0a91d)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 21.0.7, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-60-generic", arch: "amd64", family: "unix"

準備

最初のpom.xmlの設定はこれくらいにしています。

    <properties>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

Error Proneを使ってみる

ドキュメントに従って、Error Proneをインストールしてみます。

Installation

Apache Mavenの場合は、Maven Compiler Pluginに設定してインストールします。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.14.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-XDcompilePolicy=simple</arg>
                        <arg>--should-stop=ifError=FLOW</arg>
                        <arg>-Xplugin:ErrorProne</arg>
                    </compilerArgs>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>com.google.errorprone</groupId>
                            <artifactId>error_prone_core</artifactId>
                            <version>2.38.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

このあたりですね。

                        <arg>-Xplugin:ErrorProne</arg>


                    <annotationProcessorPaths>
                        <path>
                            <groupId>com.google.errorprone</groupId>
                            <artifactId>error_prone_core</artifactId>
                            <version>2.38.0</version>
                        </path>
                    </annotationProcessorPaths>

では、GitHubリポジトリーのREADME.mdに載っているサンプルを使って試してみます。

GitHub - google/error-prone: Catch common Java mistakes as compile-time errors

こちらですね。

src/main/java/org/littlewings/errorprone/ShortSet.java

package org.littlewings.errorprone;

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());
    }
}

コンパイル

$ mvn compile

すると、コンパイルに失敗しました…。

[INFO] Compiling 1 source file with javac [debug release 21] to target/classes
コンパイラで例外が発生しました(21.0.7)。バグ・データベース(https://bugs.java.com)で重複がないかをご確認のうえ、Javaのバグ・レポート・ページ(https://bugreport.java.com)から、Javaコンパイラに対するバグの登録をお願いいたします。レポートには、該当のプログラム、次の診断内容、およびJavaコンパイラに渡されたパラメータをご入力ください。ご協力ありがとうござ います。
java.lang.IllegalAccessError: class com.google.errorprone.BaseErrorProneJavaCompiler (in unnamed module @0x3380ca3d) cannot access class com.sun.tools.javac.api.BasicJavacTask (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.api to unnamed module @0x3380ca3d
        at com.google.errorprone.BaseErrorProneJavaCompiler.addTaskListener(BaseErrorProneJavaCompiler.java:85)
        at com.google.errorprone.ErrorProneJavacPlugin.init(ErrorProneJavacPlugin.java:34)
        at jdk.compiler/com.sun.tools.javac.api.BasicJavacTask.initPlugin(BasicJavacTask.java:256)
        at jdk.compiler/com.sun.tools.javac.api.BasicJavacTask.initPlugins(BasicJavacTask.java:230)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.prepareCompiler(JavacTaskImpl.java:204)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:101)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
        at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(JavaxToolsCompiler.java:126)
        at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(JavacCompiler.java:214)
        at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1226)
        at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:225)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:126)
        at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2(MojoExecutor.java:328)
        at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute(MojoExecutor.java:316)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:174)
        at org.apache.maven.lifecycle.internal.MojoExecutor.access$000(MojoExecutor.java:75)
        at org.apache.maven.lifecycle.internal.MojoExecutor$1.run(MojoExecutor.java:162)
        at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute(DefaultMojosExecutionStrategy.java:39)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:159)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:105)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:73)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:53)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:118)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:261)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:173)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:101)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:906)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:283)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:206)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:255)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:201)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:361)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:314)

ドキュメントを見返すと、設定が足りないようです。

Installation

Apache Mavenの設定を追加します。

.mvn/jvm.config

--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED

再度コンパイル

$ mvn compile

今度は動作するようになりました。

[INFO] --- compiler:3.14.0:compile (default-compile) @ error-prone-example ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 21] to target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /path/to//src/main/java/org/littlewings/errorprone/ShortSet.java:[11,21] [CollectionIncompatibleType] Argument 'i - 1' should not be passed to this method; its type int is not compatible with its collection's type argument Short
    (see https://errorprone.info/bugpattern/CollectionIncompatibleType)
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.162 s
[INFO] Finished at: 2025-06-15T22:39:25+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.14.0:compile (default-compile) on project error-prone-example: Compilation failure
[ERROR] /path/to/src/main/java/org/littlewings/errorprone/ShortSet.java:[11,21] [CollectionIncompatibleType] Argument 'i - 1' should not be passed to this method; its type int is not compatible with its collection's type argument Short
[ERROR]     (see https://errorprone.info/bugpattern/CollectionIncompatibleType)
[ERROR]
[ERROR] -> [Help 1]

ひとまず、使い方の雰囲気はわかった感じですね。

あとは使っていって慣れていく感じでしょう。

検出するバグパターンの有効化、無効化

実験的に位置づけられているバグパターンはデフォルトでは無効になっているようなので、有効にするにはどうすれば
いいのかなと見てみたら、-Xep:<checkName>[:severity]で指定するようですね。

Command-line flags

severityを指定することで、バグパターンの重要度を変更できたりするようです。

また、一括で設定するオプションもあるようですね。

  • -XepAllErrorsAsWarnings
  • -XepAllSuggestionsAsWarnings
  • -XepAllDisabledChecksAsWarnings
  • -XepDisableAllChecks
  • -XepDisableAllWarnings
  • -XepDisableWarningsInGeneratedCode

おわりに

Googleが開発しているJavaの静的解析ツール、Error Proneを試してみました。

この位置づけの静的解析ツールといえばSpotBugsかなと思っていたのですが、どうもカバー範囲が異なるみたいでどちらかを
選ぶ感じではなさそうですね。

なんとなく選ぶ印象でいたので、それぞれ使っていこうかなと思います。




以上の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/06/15/230411より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14