I get the following (confusing) warning when using null analysis based on annotations in which an array is involved:
Null type safety (type annotations): The expression of type 'int[]' needs unchecked conversion to conform to 'int @Nullable[]'
This happens when I pass unannotated int[] to the int @Nullable[] parameter.
It is surprising. Usually this is only a problem if you accept a value with a null value and try to pass it to the nonnull parameter, but I do the opposite - taking a known non-zero (albeit not annotated) array and passing it to the method ( Arrays.equals ), which takes null values.
Also this is not a problem with objects without an array. Typically, a variable or return (unannotated, non-array) type T can be assigned to @Nullable T
So my question is , why does this change when T is an array type ?
My class is a hashable / peer proxy for a native class that uses int[] (taken from a C ++ function) as a unique identifier. My package uses annotation-based null analysis, and a third-party package (with a native class) does not.
Here's a drop down version that shows the problem:
TagKey.java:
package example; import java.util.Arrays; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import other.Tag; import com.google.common.collect.Interner; import com.google.common.collect.Interners; public class TagKey { private TagKey(Tag tag) { this.tag = tag; } public static TagKey forTag(Tag tag) { TagKey candidateKey = new TagKey(tag); return INTERNER.intern(candidateKey); } @Override public int hashCode() { return Arrays.hashCode(this.tag.getUniqueIdentifier()); } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } else if (obj == null) { return false; } else if (getClass() != obj.getClass()) { return false; } else { return ((TagKey) obj).hasMatchingIdentifier(this.tag.getUniqueIdentifier());
package-info.java:
@org.eclipse.jdt.annotation.NonNullByDefault package example;
Tag.java: (partial)
package other; public class Tag { public native int[] getUniqueIdentifier();
The workaround I'm currently using is:
public boolean hasMatchingIdentifier(@Nullable Object id) { return id instanceof int[] && Arrays.equals(this.tag.getUniqueIdentifier(), (int[])id); }
I would prefer to avoid these approaches:
- Adding
@SuppressWarnings("null") to TagKey or its equals method (the production version is a bit more complicated and has a high risk of embarrassing NPE.)
Notes:
- My JDT version is 3.10.0.v20140606-1215
- I made a mistake
@Nullable int[] id declaring @Nullable int[] id . Surprisingly, there was no warning message for this, although this implies that the primitive int elements may be null , which is clearly incorrect.