--- title: Nullability Maven Plugin で Maven ユーザーが JSpecify/NullAway を使いやすくする summary: この記事では、JSpecifyとNullAwayをMavenで導入し、Nullability Maven Pluginで設定を簡略化する方法を紹介します. tags: ["NullAway", "JSpecify", "Maven", "Java"] categories: ["Programming", "Java", "Maven", "NullAway"] date: 2026-02-24T06:13:16.498Z updated: 2026-02-24T06:13:16.497Z --- ### JSpecify とは? [JSpecify](https://jspecify.dev/) とは、Java の nullability アノテーションを標準化するためのオープンソースプロジェクトです。 Java エコシステムでは従来、`@Nullable` や `@NonNull` といったアノテーションが JetBrains、FindBugs、Checker Framework など複数のライブラリでバラバラに定義されており、互換性の問題がありました。JSpecify はこれを統一し、ツール間で共通して使える仕様を提供することを目的としています。 2006 年頃に提案された Java のソフトウェア欠陥検出用アノテーションの JCP 標準化仕様に JSR‑305(事実上廃止)がありましたが、JSpecify は型引数やジェネリクスに対する nullability の扱いなど、JSR‑305 では不十分だった領域をカバーしています。 `org.jspecify.annotations` パッケージ配下に `@Nullable`、`@NonNull`、`@NullMarked` などを定義しており、静的解析ツールや IDE がこれらを認識することで、より正確な null チェックが可能になります。 Spring Framework 7 は JSpecify に対応し、null を返すメソッドや null を渡してもよい引数には明示的に `@Nullable` をつけるようになりました。それ以外では null を返さず、null の設定も許容しません。 詳しくは [こちらのブログ記事](https://spring.io/blog/2025/11/12/null-safe-applications-with-spring-boot-4) を参照してください。 JSpecify のアノテーションを使用することで、適切な null チェックが行われていないコードに対して、IDE は警告を表示できます。 しかし、これ単体ではコンパイルエラーを発生させることはありません。 ### NullAway とは? NullAway は、Java の NullPointerException を静的解析で検出するツールです。[Error Prone](https://errorprone.info/) プラグインとして動作し、ビルド時に null 安全性の違反を警告・エラーとして報告します。 JSpecify や JSR‑305 のアノテーションを認識し、「`@Nullable` が付いていない参照は non-null とみなす」というオプトアウト方式を採用しています。これにより既存コードベースへの段階的な導入がしやすい設計になっています。 NullAway と JSpecify を組み合わせることによって、適切な null チェックが行われていないコードに対して、コンパイルエラーを発生させることができるようになります。 例えば、次のコードを NullAway が有効な状態でコンパイルします。 ```java package com.example.foo; import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; @Component public class Foo { private final RestClient restClient; public Foo(RestClient.Builder restClientBuilder) { this.restClient = restClientBuilder.build(); } public String getFoo() { return this.restClient.get().uri("http://example.com/foo").retrieve().body(String.class); } } ``` すると、次のコンパイルエラーが発生します。 ``` [ERROR] /Users/toshiaki/.../Foo.java:[16,2] error: [NullAway] returning @Nullable expression from method with @NonNull return type ``` `RestClient` の `body` メソッドには次のように `@Nullable` アノテーションがついており、null を返す可能性があるのに、何もアノテーションやチェックを行わずに return しているからです。 ```java /** * Extract the body as an object of the given type. * @param bodyType the type of return value * @param the body type * @return the body, or {@code null} if no response body was available * @throws RestClientResponseException by default when receiving a * response with a status code of 4xx or 5xx. Use * {@link #onStatus(Predicate, ErrorHandler)} to customize error response * handling. */ @Nullable T body(Class bodyType); ``` 次のように null の場合に対処するコードを書く、あるいはメソッドに `@Nullable` をつけて、null を返す可能性を伝播させることでコンパイルエラーを取り除くことができます。 ```java package com.example.foo; import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; import java.util.Objects; @Component public class Foo { private final RestClient restClient; public Foo(RestClient.Builder restClientBuilder) { this.restClient = restClientBuilder.build(); } public String getFoo() { return Objects.requireNonNull(this.restClient.get().uri("http://example.com").retrieve().body(String.class), "Response body must not be null"); } } ``` なお、何もアノテーションを指定しない場合に non-null として扱うようにするには、クラスまたはパッケージに `@NullMarked` アノテーションをつける必要があります。 上記の例では次のような `package-info.java` を用意してあります。 ```java @NullMarked package com.example.foo; import org.jspecify.annotations.NullMarked; ``` ### JSpecify/NullAway を Maven で使う ここまでで JSpecify/NullAway を使うことで、強制的に null チェックができるようになることがわかりました。さて、これを Maven に組み込むにはどうすればよいでしょうか。 次の `maven-compiler-plugin` に次のような設定が必要です(要: JDK 22+)。 ```xml org.apache.maven.plugins maven-compiler-plugin 3.15.0 com.google.errorprone error_prone_core 2.47.0 com.uber.nullaway nullaway 0.13.1 true -XDcompilePolicy=simple --should-stop=ifError=FLOW -Xplugin:ErrorProne -XepDisableAllChecks -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:JSpecifyMode=true -Xep:NullAway:ERROR -XepExcludedPaths:(.*/test/java/.*|.*/target/generated-sources/.*) -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED ``` コピー&ペーストすればよいのですが、Maven プロジェクトの量が多いと管理が大変になります… ### Nullability Maven Plugin の導入 Nullability Maven Plugin はこの `pom.xml` のボイラープレートを取り除いてくれる Maven プラグインです。 https://github.com/making/nullability-maven-plugin 前述の設定は Nullability Maven Plugin を使うと、次のように簡略化されます。 ```xml org.apache.maven.plugins maven-compiler-plugin 3.15.0 am.ik.maven nullability-maven-plugin 0.3.0 true configure ``` `maven-compiler-plugin` に自身で設定した内容があれば自動でマージされます。 > [!TIP] > `mvn help:effective-pom` でマージされた内容を確認できます。 このプラグイン自体の制約ではありませんが、NullAway の JSpecify Mode を使用するには JDK 22 以上でコンパイルする必要がありますが、ターゲットは 17 でも構いません。どうしても古いバージョンの JDK(17 または 21)でコンパイルしたい場合は、[こちら](https://github.com/making/nullability-maven-plugin?tab=readme-ov-file#requirements) を参照してください。 ### package-info.java の自動生成 JSpecify を使う上で面倒なのが、`package-info.java` の作成です。`@NullMarked` のついた `package-info.java` は各サブパッケージに作成する必要があり、つい作成を忘れがちです。 Nullability Maven Plugin はデフォルトで、`@NullMarked` がついていないクラス/パッケージがあればエラーにします。 また、次の設定で `package-info.java` をビルド時に自動生成させることもできます。 ```xml am.ik.maven nullability-maven-plugin 0.3.0 true configure generate-package-info ``` 生成させるディレクトリの設定は [こちら](https://github.com/making/nullability-maven-plugin?tab=readme-ov-file#generating-package-infojava-automatically) を参照してください。 --- Nullability Maven Plugin で Maven ユーザーが簡単に JSpecify / NullAway を導入できる方法を紹介しました。ぜひ試してください。