如何告诉检查器遗留方法将接受 Nullable 类型?
How to tell checker that a legacy method will accept Nullable types?
考虑一下:
@Nullable Object obj = null;
Optional<Object> optional = Optional.ofNullable(obj);
这失败了,因为 checker-framework 假定 ofNullable
不能接受 null
值(毕竟,它的参数没有被标记为 @Nullable)。
有什么好方法可以告诉 checker-framework 这个方法(或遗留代码中我无法更改的其他方法)在任何地方都接受 @Nullable 类型而不必在任何地方更改代码?
我不确定你为什么说 "its parameter is not marked as @Nullable"。
当我查看文件时
checker-framework/checker/jdk/nullness/src/java/util/Optional.java,
我看到以下带注释的方法:
public static <T> Optional<@NonNull T> ofNullable(@Nullable T value) {
return value == null ? empty() : of(value);
}
此外,当我运行 Checker Framework 在下面的代码中,它没有发出警告。
// run like this:
// javacheck -g TestOptional.java -processor nullness
import java.util.*;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.NonNull;
public class TestOptional {
void m() {
@Nullable Object obj = null;
Optional<Object> optional1 = Optional.ofNullable(obj);
}
}
我不确定你的案例是怎么回事,因为你没有提供完整的测试用例,你没有说出你的命令 运行,也没有给出实际的错误信息。 (您确实提供了诊断,但我不确定它是否准确。)
也许提供更多详细信息可以更好地理解您的问题。
编辑:此答案基于@mernst 在评论和Checker Framework's Issue tracker
中的帮助
如果您像我一样不想或不能使用带注释的 JDK,您将 运行 陷入此问题。
注意:在我工作过的大多数 Java 商店中,我们根本无法切换我们使用的编译器或提供 "custom" JDK(这真是不可思议).为了便于移植,对于初学者,我必须将自定义 JDK 添加到我的源存储库,或者将其分发到每台机器,包括代码编译的 CI 服务器,并确保它们在不同的 OS 中处于完全相同的路径中。就是不帅
解决方案是提供 stub classes 并将它们作为参数传递给 javac
进程。
这可以使用您用来编译的任何工具轻松完成。
例如,使用 Maven(使用标准 compiler plugin):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessors>
<annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
</annotationProcessors>
<compilerArgs>
<arg>-Astubs=checkerframework/stubs</arg>
<arg>-AstubWarnIfNotFound</arg>
</compilerArgs>
</configuration>
</plugin>
您还需要将这些依赖项添加到您的项目中:
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>1.9.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker</artifactId>
<version>1.9.2</version>
<optional>true</optional>
</dependency>
这里,checkerframework/stubs
是一个目录(相对于 pom 的位置),包含 stubs。对于 Optional,我的存根看起来像这样(奇怪的是,存根必须命名为 *.astub,所以这个文件被称为 Optional.astub):
package java.util;
import org.checkerframework.checker.interning.qual.*;
import javax.annotation.Nullable;
class Optional<T> {
static <T> Optional<T> ofNullable(@Nullable T value);
@Nullable T orElse(@Nullable T other);
}
这种方法很简单,需要很少的工作,根本不会混淆我使用的编译器或 Java 库,确保这些定义只与 checkerframework 一起使用(这样我就可以,例如,将其添加到 Maven 配置文件并仅在我想通过简单地传递 Maven 参数时启用它),将跨机器和 OS 工作,而无需以真正的 Java 做事方式进行先前设置.
考虑一下:
@Nullable Object obj = null;
Optional<Object> optional = Optional.ofNullable(obj);
这失败了,因为 checker-framework 假定 ofNullable
不能接受 null
值(毕竟,它的参数没有被标记为 @Nullable)。
有什么好方法可以告诉 checker-framework 这个方法(或遗留代码中我无法更改的其他方法)在任何地方都接受 @Nullable 类型而不必在任何地方更改代码?
我不确定你为什么说 "its parameter is not marked as @Nullable"。 当我查看文件时 checker-framework/checker/jdk/nullness/src/java/util/Optional.java, 我看到以下带注释的方法:
public static <T> Optional<@NonNull T> ofNullable(@Nullable T value) {
return value == null ? empty() : of(value);
}
此外,当我运行 Checker Framework 在下面的代码中,它没有发出警告。
// run like this:
// javacheck -g TestOptional.java -processor nullness
import java.util.*;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.NonNull;
public class TestOptional {
void m() {
@Nullable Object obj = null;
Optional<Object> optional1 = Optional.ofNullable(obj);
}
}
我不确定你的案例是怎么回事,因为你没有提供完整的测试用例,你没有说出你的命令 运行,也没有给出实际的错误信息。 (您确实提供了诊断,但我不确定它是否准确。)
也许提供更多详细信息可以更好地理解您的问题。
编辑:此答案基于@mernst 在评论和Checker Framework's Issue tracker
中的帮助如果您像我一样不想或不能使用带注释的 JDK,您将 运行 陷入此问题。
注意:在我工作过的大多数 Java 商店中,我们根本无法切换我们使用的编译器或提供 "custom" JDK(这真是不可思议).为了便于移植,对于初学者,我必须将自定义 JDK 添加到我的源存储库,或者将其分发到每台机器,包括代码编译的 CI 服务器,并确保它们在不同的 OS 中处于完全相同的路径中。就是不帅
解决方案是提供 stub classes 并将它们作为参数传递给 javac
进程。
这可以使用您用来编译的任何工具轻松完成。
例如,使用 Maven(使用标准 compiler plugin):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessors>
<annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
</annotationProcessors>
<compilerArgs>
<arg>-Astubs=checkerframework/stubs</arg>
<arg>-AstubWarnIfNotFound</arg>
</compilerArgs>
</configuration>
</plugin>
您还需要将这些依赖项添加到您的项目中:
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>1.9.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker</artifactId>
<version>1.9.2</version>
<optional>true</optional>
</dependency>
这里,checkerframework/stubs
是一个目录(相对于 pom 的位置),包含 stubs。对于 Optional,我的存根看起来像这样(奇怪的是,存根必须命名为 *.astub,所以这个文件被称为 Optional.astub):
package java.util;
import org.checkerframework.checker.interning.qual.*;
import javax.annotation.Nullable;
class Optional<T> {
static <T> Optional<T> ofNullable(@Nullable T value);
@Nullable T orElse(@Nullable T other);
}
这种方法很简单,需要很少的工作,根本不会混淆我使用的编译器或 Java 库,确保这些定义只与 checkerframework 一起使用(这样我就可以,例如,将其添加到 Maven 配置文件并仅在我想通过简单地传递 Maven 参数时启用它),将跨机器和 OS 工作,而无需以真正的 Java 做事方式进行先前设置.