Skip to content

Commit 7075c1e

Browse files
committed
null away blog post
1 parent 2ae6675 commit 7075c1e

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

posts/2025-11-21-null-away.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
title: Micronaut NullAway and JSPecify
3+
summary: In this blog post, I show you how to configure a Micronaut 4 application to use JSpecify and NullAway to protect you from NPEs (Null Pointer Exceptions).
4+
date_published: 2025-11-21T11:32:42+01:00
5+
keywords:micronaut
6+
external_url: http://github.com/uber/NullAway
7+
---
8+
9+
# [%title]
10+
11+
[%summary]
12+
13+
## [NullAway](http://github.com/uber/NullAway):
14+
15+
> NullAway is a tool to help eliminate NullPointerExceptions (NPEs) in your Java code. To use NullAway, first add @Nullable annotations in your code wherever a field, method parameter, or return value may be null. Given these annotations, NullAway performs a series of type-based, local checks to ensure that any pointer that gets dereferenced in your code cannot be null.
16+
17+
18+
## JSpecify Dependency
19+
20+
Since Micronaut 4.10, Micronaut BOM contains the JSpecify dependency. Thus, you can add the following dependency to your project without specifying the version:
21+
22+
```xml
23+
<dependency>
24+
<groupId>org.jspecify</groupId>
25+
<artifactId>jspecify</artifactId>
26+
</dependency>
27+
```
28+
29+
## NullAway with Gradle
30+
31+
[GitHub Repository with a Gradle Micronaut Application which uses `NullAway`](https://github.com/sdelamo/micronaut-gradle-nullaway-demo/tree/main)
32+
33+
To use [NullAway](http://github.com/uber/NullAway) in a Gradle Micronaut Application. You need to add the [Gradle error prone plugin](https://github.com/tbroyer/gradle-errorprone-plugin) and such configuration:
34+
35+
36+
```kotlin
37+
plugins {
38+
...
39+
..
40+
.
41+
id("net.ltgt.errorprone") version "4.3.0"
42+
}
43+
dependencies {
44+
...
45+
..
46+
.
47+
implementation("org.jspecify:jspecify")
48+
errorprone("com.uber.nullaway:nullaway:0.12.12")
49+
errorprone("com.google.errorprone:error_prone_core:2.44.0")
50+
}
51+
tasks.withType<JavaCompile>().configureEach {
52+
options.errorprone {
53+
check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR)
54+
option("NullAway:AnnotatedPackages", example.micronaut")
55+
if (name.lowercase().contains("test")) {
56+
disable("NullAway")
57+
}
58+
}
59+
}
60+
```
61+
62+
- `check("NullAway", CheckSeverity.ERROR)` sets `NullAway` issues to the error level.
63+
- `option("NullAway:AnnotatedPackages", “example.micronaut”)` tells `NullAway` that source code in packages under the `example.micronaut` namespace should be checked for null dereferences and proper usage of `@Nullable ` annotations, and that class files in these packages should be assumed to have correct usage of `@Nullable`.
64+
- Then, it disables `NullAway` on test code.
65+
66+
[These instructions are described in the NullAway README.md file](https://github.com/uber/NullAway?tab=readme-ov-file#java-non-android).
67+
68+
## NullAway with Maven
69+
[GitHub Repository with a Maven Micronaut Application which uses `NullAway`](https://github.com/sdelamo/micronaut-maven-nullaway-demo/tree/main)
70+
71+
```xml
72+
73+
<?xml version="1.0" encoding="UTF-8"?>
74+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
75+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
76+
...
77+
..
78+
.
79+
<properties>
80+
...
81+
..
82+
.
83+
<error-prone.version>2.29.2</error-prone.version>
84+
<nullaway.version>0.12.12</nullaway.version>
85+
</properties>
86+
...
87+
..
88+
.
89+
<dependencies>
90+
<dependency>
91+
<groupId>org.jspecify</groupId>
92+
<artifactId>jspecify</artifactId>
93+
<version>1.0.0</version>
94+
</dependency>
95+
...
96+
..
97+
.
98+
</dependencies>
99+
<build>
100+
<plugins>
101+
...
102+
..
103+
.
104+
<plugin>
105+
<groupId>org.apache.maven.plugins</groupId>
106+
<artifactId>maven-compiler-plugin</artifactId>
107+
<configuration>
108+
<compilerArgs>
109+
<arg>-XDcompilePolicy=simple</arg>
110+
<arg>--should-stop=ifError=FLOW</arg>
111+
<arg>-Xplugin:ErrorProne -Xep:NullAway:ERROR -XepOpt:NullAway:AnnotatedPackages=example.micronaut</arg>
112+
<arg>-Amicronaut.processing.group=mn.maven.jspecify</arg>
113+
<arg>-Amicronaut.processing.module=mn-maven-jspecify</arg>
114+
</compilerArgs>
115+
<annotationProcessorPaths combine.children="append">
116+
<path>
117+
<groupId>com.google.errorprone</groupId>
118+
<artifactId>error_prone_core</artifactId>
119+
<version>${error-prone.version}</version>
120+
</path>
121+
<path>
122+
<groupId>com.uber.nullaway</groupId>
123+
<artifactId>nullaway</artifactId>
124+
<version>${nullaway.version}</version>
125+
</path>
126+
<!-- Existing Micronaut processors -->
127+
...
128+
..
129+
.
130+
</annotationProcessorPaths>
131+
</configuration>
132+
</plugin>
133+
</plugins>
134+
</build>
135+
</project>
136+
```
137+
138+
The above example adds two annotation processors. [Error Prone](https://errorprone.info/docs/flags#maven) and [NullAway](https://github.com/uber/NullAway/wiki/Configuration).
139+
140+
The previous code sample [configures `NullAway`](https://github.com/uber/NullAway/wiki/Configuration):
141+
142+
143+
- `-XepOpt:NullAway:AnnotatedPackages` sets the list of packages that should be considered properly annotated according to the NullAway convention
144+
- `-Xep:NullAway:ERROR` sets the NullAway check severity to ERROR, which should cause compilation to fail when `NullAway` violations are found.
145+
146+
As [described in the error prone Maven documentation](https://errorprone.info/docs/installation#maven), I added a `.mvn/jvmconfig` file with the following content:
147+
148+
```
149+
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
150+
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
151+
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
152+
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
153+
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
154+
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
155+
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
156+
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
157+
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
158+
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
159+
```
160+
161+
A failure looks like:
162+
163+
```
164+
[INFO] ------------------------------------------------------------------------
165+
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.14.1:compile (default-compile) on project mn-maven-jspecify: Compilation failure
166+
[ERROR] /Users/sdelamo/github/sdelamo/micronaut-maven-nullaway-demo/src/main/java/example/micronaut/GreetingController.java:[21,39] [NullAway] dereferenced expression greetingService.greet() is @Nullable
167+
[ERROR] (see http://t.uber.com/nullaway )
168+
[ERROR]
169+
[ERROR] -> [Help 1]
170+
[ERROR]
171+
```
172+
173+

0 commit comments

Comments
 (0)