The line public static <T> java.util.@Nullable Optional<T> toJavaUtil
is written like this, because the usual style public static <T> @Nullable java.util.Optional<T> toJavaUtil
is invalid. This is defined in the JLS §9.7.4:
It is a compile-time error if an annotation of type T applies to a type (or any part of a type) in a type context, and T is applicable in type contexts, and the annotation is not admissible.
For example, assume an annotation type TA which is meta-annotated with just @Target(ElementType.TYPE_USE)
. The terms @TA java.lang.Object
and java.@TA lang.Object
are illegal because the simple name to which @TA is closest is classified as a package name. On the other hand, java.lang.@TA Object
is legal.
The type declaration of org.checkerframework.checker.nullness.qual@Nullable
is:
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
So it is applying to this rule.
That this structure doesn't break the execution, since package java.util
and class name Optional
were split, can be seen when we look at the compiled code using javap -c [compiled class name]
:
class just.a.test.Main {
just.a.test.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static <T> java.util.Optional<T> toJavaUtil(blub.Optional<T>);
Code:
0: aload_0
1: ifnonnull 8
4: aconst_null
5: goto 12
8: aload_0
9: invokevirtual #2 // Method blub/Optional.toJavaUtil:()Ljava/util/Optional;
12: areturn
}
(blub.Optional
is a local class where I copied the Guava code in, in order to get a minimal example to de-/compile)
As you can see, the annotation doesn't exist there anymore. It is only a marker for the compiler to prevent a warning when the method returns null (and a hint for the source code readers), but it won't be included in the compiled code.
This compiler error also applies to variables like:
private @Nullable2 java.util.Optional<?> o;
But can become acceptable when the annotation additionally gets the target type ElementType.FIELD
, as written in the same JLS clause:
If TA is additionally meta-annotated with @Target(ElementType.FIELD)
, then the term @TA java.lang.Object
is legal in locations which are both declaration and type contexts, such as a field declaration @TA java.lang.Object f;
. Here, @TA is deemed to apply to the declaration of f (and not to the type java.lang.Object) because TA is applicable in the field declaration context.