I have some java code which looks like below
import org.checkerframework.checker.nullness.qual.Nullable;
abstract class Foo {
abstract @Nullable String getFoo();
void foo() {
if (getFoo() != null) {
bar(getFoo());
}
}
void bar(String str) {
str.charAt(1);
}
}
Which gives me the error
Error: [argument.type.incompatible] incompatible types in argument.
found : @Initialized @Nullable String
required: @Initialized @NonNull String
which is undestandable as getFoo
as been decorated with Nullable
.
can I prevent this without modifying the bar
method ? both methods getFoo
and bar
are out of my control for modifications.
What are the solutions to resolve this ?
In general, the Nullness Checker is correct that the given code might throw a NullPointerException, because getFoo()
might return different values on different invocations. You can express that getFoo()
returns the same value on every invocation (on the same receiver) by using the @Deterministic
method annotation:
import org.checkerframework.dataflow.qual.Deterministic;
import org.checkerframework.checker.nullness.qual.Nullable;
abstract class Foo {
@Deterministic
abstract @Nullable String getFoo();
void foo() {
if (getFoo() != null) {
bar(getFoo());
}
}
void bar(String str) {
str.charAt(1);
}
}
This is discussed in the Checker Framework manual.
If you cannot directly add @Deterministic
to a library, you can write a stub file with that annotation and use it while type-checking your code.