2025008. Adoption of JSpecify for Null-Safety¶
Status: Accepted – Partially implemented accross multiple PRs
Deciders: Hiroshi Miura, Jean-Christophe Helary, OmegaT Development Team
Date: 2025-11-18
Context and Problem Statement¶
NullPointerExceptions (NPEs) are a common source of runtime errors in Java applications. While static code analysis tools (like SpotBugs and NullAway) can detect potential nullability issues, they rely on accurate annotations to function effectively.
Historically, the Java ecosystem has suffered from a fragmentation of nullability annotations
(javax.annotation, com.intellij.annotations, android.support.annotation, etc.),
leading to inconsistent analysis and library interoperability issues.
In OmegaT:
We have previously relied on transitive dependencies (e.g., via
language-tool) or IDE-specific annotations (IntelliJ) for null checks.Discussions in December 2022 identified the need for a standard approach.
In March 2025, an RFC was raised to actively use nullity annotations to reduce the 860+ warnings/errors detected by SpotBugs.
Modern Java development practices (influenced by Kotlin and other null-safe languages) advocate for explicit nullability definitions.
We need a standardized, robust, and modern way to declare nullability intent in the codebase to improve quality assurance and developer productivity.
Decision Drivers¶
Standardization: The need to move away from proprietary or deprecated annotation libraries (like JSR-305).
Code Quality: Reducing the risk of NPEs through compile-time checks and static analysis.
Tooling Support: Ensuring compatibility with modern static analysis tools like NullAway and SpotBugs.
Clarity: Making APIs self-documenting regarding whether they accept or return null.
Considered Options¶
Option 1: Continue using ad-hoc annotations (IntelliJ/FindBugs).
Pros: No immediate changes required.
Cons: Fragmentation, lack of standard enforcement, dependency on specific IDEs or older libraries.
Option 2: Adopt JSpecify (
org.jspecify.annotations).Pros: Industry standard for JVM nullability, supported by major industry players (Google, JetBrains, etc.), provides
@NullMarkedfor comprehensive defaults.Cons: Requires adding a dependency (though lightweight), requires migration effort.
Decision¶
We will adopt JSpecify as the standard library for nullability annotations in the OmegaT project.
Dependency: We add
org.jspecify:jspecifyas a compile-time dependency.Default Non-Null Strategy: We will utilize the
@NullMarkedannotation at the package level (viapackage-info.java) or class level. This inverts the default behavior: everything is assumed non-null unless specified otherwise.Explicit Nullable: We will use
@Nullableexplicitly for any field, parameter, or return value that can legitimately be null.Migration: Existing annotations (from IntelliJ or other sources) will be replaced with JSpecify equivalents progressively.
This decision aligns with ADR 2025003 Comprehensive Static Code Analysis Strategy.
Consequences¶
Positive¶
Reduced Bugs: Static analysis tools can now rigorously enforce null safety, catching bugs before runtime.
Clearer API Contracts: Developers immediately know if a method returns
nullor if an argument requires a non-null value.Reduced Boilerplate: Using
@NullMarkedreduces the visual noise of having to annotate every single non-null parameter with@NonNull.Modernization: Aligns OmegaT source code with current Java ecosystem standards.
Negative¶
Initial Noise: Enabling stricter checks may result in a temporary spike in linter warnings that need to be resolved or suppressed.
Learning Curve: Developers must strictly adhere to annotating nullable types, otherwise, the “default non-null” assumption may hide issues (though tools usually catch inconsistencies).
Short‑term Workload Increase: The project will experience a sustained period of warning cleanup and annotation work across modules (e.g., MissingOverride, Javadoc tag hygiene, nullability contracts). This adds overhead until the codebase reaches a new steady state with low warning counts.
CI Signal‑to‑Noise Risk: The elevated number of warnings can obscure genuinely critical findings unless baselines and thresholds are tuned.
Note: The observed messages reported as “errors” are warnings emitted by Error Prone/NullAway and related linters; the build remains successful. The heightened visibility is intentional, following the introduction of Error Prone to the core (PR #1496) and later expansion to modules (PR #1692), and supports the migration to JSpecify.
Implementation Progress¶
The adoption of JSpecify is being carried out incrementally across the codebase through focused pull requests: