基于注释的空分析 - 警告仅出现在数组参数中

fin*_*nnw 5 java eclipse annotations nullable eclipse-jdt

当使用基于注释的空分析时,我会得到以下(令人困惑的)警告,其中涉及一个数组:

Null type safety (type annotations): The expression of type 'int[]' needs unchecked conversion to conform to 'int @Nullable[]'

当我将未注释int[]int @Nullable[]参数传递给参数时会发生这种情况.

这是令人惊讶的.通常只有一个问题,如果你取一个可空的值并尝试将它传递给一个非空参数,但我正在做相反的事情 - 采用一个已知的非null(虽然没有注释)数组并将其传递给一个方法(Arrays.equals)确实接受空值.

此外,它似乎不是非数组对象的问题.通常,T可以将(未注释的,非数组)类型的变量或返回分配给a @Nullable T.

所以我的问题是为什么在T数组类型时这会改变


我的类是一个可清除/可比较的代理,用于使用int[](取自C++函数)作为唯一标识符的本机类.我的包使用基于注释的空分析,而第三方包(使用本机类)则不使用.

这是一个显示问题的简化版本:

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()); // Warning appears here
        }
    }

    public boolean hasMatchingIdentifier(int @Nullable[] id) {
        return Arrays.equals(this.tag.getUniqueIdentifier(), id);
    }

    @SuppressWarnings("null") // Guava cannot use type parameter annotations due to backward compatibility with Java 6
    private static final Interner<TagKey> INTERNER = Interners.newWeakInterner();

    private final Tag tag;

}
Run Code Online (Sandbox Code Playgroud)

package-info.java:

/**
 * @author finnw
 *
 */
@org.eclipse.jdt.annotation.NonNullByDefault
package example;
Run Code Online (Sandbox Code Playgroud)

Tag.java :(部分)

package other;

public class Tag {
    public native int[] getUniqueIdentifier(); // Currently returns a fresh array on each call, but may change in the near future to reuse a single array
}
Run Code Online (Sandbox Code Playgroud)

我目前使用的解决方法:

    public boolean hasMatchingIdentifier(@Nullable Object id) {
        return id instanceof int[] &&
               Arrays.equals(this.tag.getUniqueIdentifier(), (int[])id);
    }
Run Code Online (Sandbox Code Playgroud)

我宁愿避免这些方法:

  • 添加@SuppressWarnings("null")TagKey或它的equals方法(量产版是较为复杂和有尴尬的NPE的高风险.)

笔记:

  • 我的JDT版本是3.10.0.v20140606-1215
  • 早些时候我犯了错误的声明@Nullable int[] id.令人惊讶的是,没有任何警告信息,即使它暗示原始int元素可能null明显错误.

Sea*_*der 1

添加这个方法:

@SuppressWarnings("null")
public static int @Nullable[] getUniqueIdentifier(Tag tag) {
    return tag.getUniqueIdentifier();
}
Run Code Online (Sandbox Code Playgroud)

然后:

return ((TagKey) obj).hasMatchingIdentifier(getUniqueIdentifier(this.tag));
Run Code Online (Sandbox Code Playgroud)

这就是为什么我忽略“来自非注释的未经检查的转换”警告,直到支持空配置文件为止,您要么在各处抑制空警告(这违背了要点),要么为每个库创建带注释的包装器方法。