Look at this simple code.
try (@Foo Stream<@Bar Baz> foo = blabla) { }
We know that @Bar is annotating Baz, and @Foo is annotating Stream (I've written a similar example here, compile it online!).
But what about this code?
void whatever(@Foo String[] args) { }
Here we have a String[] annotated with @Foo (whatever the annotation is, it's not important for this question).
My question is, is @Foo annotated on String or String[]?
It's quite important to determine the target of the annotation, since sometimes we use annotations like @NotNull to represent nullabilities of a type, and @NotNull List<String> means a list which is never null is containing some possibly null strings; List<@NotNull String> represents a list which is possibly null but the members are never null.
A possible use case: I need a @NotNull to show args is not null and another @NotNull to show the members of args are also not null? I need to annotate them both at the same time. If args is a java.util.List, I can use @NotNull List<@NotNull String>. But args is an array -- and I don't know how does the annotation affect on the type of args.
Defining @NonNull before the array level seems to do the trick (for the Checker Framework at least):
import org.checkerframework.checker.nullness.qual.NonNull;
class App {
void foo() {
String @NonNull [] bar;
bar = null; // NOK
bar = new String[1];
bar[0] = null; // NOK
}
}
Results in two errors (cf. live demo):
| No. | Type | Description | Line | Column |
|-----|-------|-----------------------------------------------------------------------------|------|--------|
| 1 | error | Error: [assignment.type.incompatible] incompatible types in assignment. | 6 | 15 |
| | | found : null | | |
| | | required: @Initialized @NonNull String @UnknownInitialization @NonNull [] | | |
| 2 | error | Error: [assignment.type.incompatible] incompatible types in assignment. | 8 | 18 |
| | | found : null | | |
| | | required: @Initialized @NonNull String | | |
To answer your actual question, see the specification, §9.7.4:
@C int @A [] @B [] f;
@Aapplies to the array typeint[][],@Bapplies to its component typeint[], and@Capplies to the element typeint.
So @Foo String[] args is actually annotating String (read as: a possibly null array of non-null strings).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With