-
Notifications
You must be signed in to change notification settings - Fork 299
Supported Annotations
This page documents the different code annotations that are supported by NullAway by default. Custom annotations can be supported for certain functionality via the command-line flags.
NullAway treats any annotation whose simple (un-qualified) name is @Nullable
as marking a parameter / return / field as nullable. Checker Framework's @NullableDecl
and javax.annotation.CheckForNull
are also supported.
For code considered annotated by NullAway, the tool assumes that the absence of a @Nullable
annotation means the type is non-null. However, there are a number of features of NullAway, such as it's optional support for acknowledging restrictive annotations in third-party jars, which involve checking for explicit @NonNull
annotations. For this purpose, NullAway treats any annotation whose simple (un-qualified) name is @NonNull
, @NonNull
, or @NotNull
, as denoting an explicitly non-null type.
While NullAway considers non-null the default in annotated code, other tools might expect any of the above annotations. In particular, the annotation javax.validation.constraints.NotNull
(and @NotEmpty
) is actually used for dynamic validation of deserialized data (see https://beanvalidation.org/1.1/spec/) and is a good candidate for being added to -XepOpt:NullAway:ExcludedFieldAnnotations=...
, since it implies external initialization of a field.
There is also optional support for treating Android's @RecentlyNullable
and @RecentlyNonNull
as @Nullable
and @NonNull
annotations, respectively.
Finally, while we strongly recommend the use of standard nullability annotations (such as org.jspecify.annotations.Nullable
or javax.annotation.Nullable
) for broader tool compatibility, NullAway supports configuring additional custom nullness annotations.
Any annotation whose simple (un-qualified) name is @Initializer
is treated as marking a method as an initializer (see here for more information on initialization checking). We also support JUnit's @Before
and @BeforeClass
for marking initializers.
NullAway has partial support for JetBrains @Contract
annotations. Some examples:
public class NullnessChecker {
@Contract("_, null -> true")
static boolean isNull(boolean flag, @Nullable Object o) { return o == null; }
@Contract("null -> false")
static boolean isNonNull(@Nullable Object o) { return o != null; }
@Contract("null -> fail")
static void assertNonNull(@Nullable Object o) { if (o == null) throw new Error(); }
@Contract("!null -> !null")
static @Nullable Object id(@Nullable Object o) { return o; }
}
For now, the @Contract
annotations are trusted, not checked. NullAway will warn if it sees a call to a method with a @Contract
annotation it recognizes as invalid.
Not all possible clauses of @Contract
annotations are fully parsed or supported by NullAway (e.g. @Contract("null, false -> fail; !null, true -> fail")
will be ignored, since NullAway cannot generally reason about the runtime truth value of the second argument).
NullAway supports the JSpecify @NullMarked
and @NullUnmarked
annotations; see the linked Javadoc for further details. Annotating a class / method as @NullMarked
means that its APIs are treated as annotated for nullness, while @NullUnmarked
means the APIs are treated as unannotated. Additionally, NullAway does not perform checks within @NullUnmarked
code. By default, classes within specified annotated packages are treated as @NullMarked
and classes outside those packages are treated as @NullUnmarked
. An individual method within a @NullMarked
class may be annotated as @NullUnmarked
.
- Precondition:
@RequiresNonNull({"class_fields"})
- Postcondition:
@EnsuresNonNull({"class_fields"})
These annotations enable setting preconditions and postconditions on class methods regarding nullability of receiver fields.
If a method is annotated with @RequiresNonNull
, NullAway assumes that @Nullable
fields given in the annotation parameter are @NonNull
while checking the method body, and ensures those fields are @NonNull
at all call sites.
If a method is annotated with @EnsuresNonNull
, it must make sure that all class fields given in the annotation parameter are @NonNull
in all executions that do not end in throwing an exception. This information is used for more precise analysis of callers of the method.
The following syntax rules apply to both annotations:
- At least one field must be specified.
- The receiver of the listed fields can only be the receiver of the method.
- All parameters given in the annotation must a field of the enclosing class (directly declared or inherited).
See the error messages page for further details on checking of these annotations.
The annotation allows you to define methods that checks the non-nullability of fields. The annotation @EnsuresNonNullIf
offers two parameters:
- The required
value
parameter, which should declare the list of fields the method ensures the non-nullability - The optional boolean
result
parameter, which indicates the boolean returned by the method when fields are non-null. The default value istrue
.
See the example below. The method hasItem
is annotated with @EnsuresNonNullIf
. It lists item
as the field that it checks for nullability. The method returns true
in case the item
is not null. The operation
method can now make use of hasItem()
to ensure that item
isn't null.
class Foo {
@Nullable private Object item;
@EnsuresNonNullIf("item")
public boolean hasItem() {
return item != null;
}
public void operation() {
if(!hasItem()) {
return;
}
// from here on, item is assumed to be non-null
}
}