I recently started updating my Java projects with Eclipse's nullability annotations. I have a JavaFX base project, containing some translation classes.
Now, in my LocalizedList, I initialize it with an element in the document tree and it recursively adds all its subelements.
@NonNullByDefault
private void locChildren(Styleable c) {
String localizable = getKey(c);
if(localizable != null) {
backingMap.put(c, localizable);
setText(c, localizable);
}
if(c instanceof MenuBar) {
MenuBar mb = (MenuBar)c;
initLoc(mb.getMenus());
} // else if ...
}
@NonNullByDefault
public void initLoc(List<? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
Now, if I left it with just this, I get the awfully long warning message
Null type safety (type annotations): The expression of type 'ObservableList<Menu>' needs unchecked conversion to conform to '@NonNull List<? extends @NonNull Styleable>', corresponding supertype is 'List<Menu>'
This is because MenuBar#getMenus() is not annotated with any nullability annotations, and to be expected.
After applying the @Nullable annotation to the List itself, the problem was not resolved. So, I added @Nullable to the wildcard. This is where I stumbled upon something confusing.
@NonNullByDefault
public void initLoc1(@Nullable List<@Nullable ? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc2(@Nullable List<@Nullable ? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc3(@Nullable List<? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
Each of these three declarations is valid and compiles fine, however only the last one makes the warning message disappear.
I would have expected the first one to be valid, as it actually annotates the "type" that is used in the method itself, and am completely confused by the second example.
What exactly is the semantic difference between these three declarations, and why does three work, while two and one do not?