Community
Participate
Working Groups
With Null analysis on, the compiler issues two bogus warnings for the following program: @org.eclipse.jdt.annotation.NonNullByDefault class Foo { static void bar(java.util.Queue<String> q) { if (q.poll() == null) { System.out.println("The queue is empty"); } } } The warnings are "Dead code" and "Redundant null check: comparing '@NonNull String' against null. It is true that the queue does not contain nulls, but q.poll may return null anyway (IF java.util.Queue had been annotated, the method poll would be @Nullable, but as it has not been annotated, the compiler shouldn't assume anything about this method). Workaround: use @org.eclipse.jdt.annotation.NonNullByDefault({DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE, DefaultLocation.FIELD})
This works exactly as designed and emphasizes the importance of bug 331651. I think you clearly understood the underlying reasoning, but let me be explicit: The declaration "E poll()" promises that the method will return a value of the actual type substituted for E. By using @NonNullByDefault of o.e.j.annotation version 2.x you are declaring the variable 'q' to have type "@NonNull Queue<@NonNull String>", hence 'E' is substituted with '@NonNull String', hence poll() is declared to return '@NonNull String'. For remove() this is the correct semantics, for poll() this is wrong. Unfortunately we don't have any hints to distinguish a situation where a type variable is intentionally used *unannotated*, to let the client's substitution take effect, from a situation that simply hasn't received the desired blessing of null annotations. Any change we would be doing here to accommodate the 'legacy' case would break the indented semantics for the other (good) case. Unless I'm missing an option how to distinguish remove() and poll() I don't see anything we can do, other than bug 331651 (with high priority). The workaround is fine, as it signals: we do not trust the analysis on @NonNull type arguments. Placing the modified NonNullByDefault on the affected method should suffice, to ensure that other methods of this type still benefit from more complete checking with @NonNull type arguments.
An even funnier example: import java.util.Optional; @org.eclipse.jdt.annotation.NonNullByDefault class Foo { static void bar() { Optional<String> o = Optional.ofNullable(foo()); System.out.println(o.orElse("undefined")); } static @org.eclipse.jdt.annotation.Nullable String foo() { return null; } } line 6: Null type mismatch (type annotations): required '@NonNull String' but this expression has type '@Nullable String'
Here we give lead to regular type inference: with a target type of Optional<@NonNull String> we infer the <T> of 'ofNullable()' to '@NonNull String', hence the method expects a nonnull string. Will be fixed when adding these (external) annotations to Optional: <T> Optional<@NonNull T> ofNullable(@Nullable T value) eventually ...
*** This bug has been marked as a duplicate of bug 331651 ***