Nullness annotations directly on type parameters are interpreted differently by different tools. — unless you are using the Checker Framework.
class Foo<@Nullable T>
To the Checker Framework, this means that a given type argument must be
nullable. For example, in the Checker Framework’s default JDK stubs,
the type argument to ThreadLocal
must be nullable.
To Kotlin, this means that the type argument can be nullable but need not be so.
If you want the Checker Framework interpretation, then keep your code as it is,
and suppress this warning. If you want the “can be nullable” interpretation,
change to class Foo<T extends @Nullable Object>
.
The effects of that change would be:
It is a behavior change for the Checker Framework, one that could even
produce local or non-local the Checker Framework failures. As discussed
above, it may be a desirable change, and it’s likely to be safe unless you
are using it with ThreadLocal
.
This is probably not a behavior change for Kotlin.
class Foo<@NonNull T>
To the Checker Framework, this means to allow any nullness for the type
argument(!). (It
sets the lower bound
to @NonNull
, which is already the default there.)
To Kotlin, this means that the type argument must be non-nullable.
Users probably want class Foo<T extends @NonNull Object>
. Or, if they’re
within the scope of @NullMarked
and they are using tools that recognize it
(such as Kotlin), they may prefer class Foo<T>
, which is equivalent but
shorter.
The effects of that change would be:
The JSpecify spec says that usages of their annotations on type parameters are unrecognized (Javadoc, spec). This specification choice is motivated by the disagreement in tool behavior discussed above.
Suppress false positives by adding the suppression annotation @SuppressWarnings("NullableTypeParameter")
to the enclosing element.