生成实现 JSR 308 "instanceof @MyAnotations"运行时检查的代码


JSR308建议向Java添加类型注释。在批准后,程序员将能够在当前允许Java类型的任何地方添加注释。这不仅包括方法/字段/局部/参数装饰,还包括构造函数调用、类型转换和最奇怪的instanceof检查。Checker框架使用JSR308来实现对象类型上的类型限定符@NonNull或字符串上的@Regex

现在Checkers所做的就是静态地分析代码。这都是编译时的检查。没关系。但我想要的是一种可以在运行时进行检查的机制。您可以申报:

@Regex String p1 = "[a-z]+";
@Regex String p1 = "[a-z)+";    // compile time error from annotation processor

我也可以写:

if (x instanceof @Regex String) ...

但这与x instanceof String没有什么不同。我需要一个编译时注释处理器运行时字节码操纵器,它允许我在instanceof检查上运行任意代码并返回布尔值。Java可以做到这一点吗?

可以。但它并不是微不足道的,并且不受可访问API的注释处理器的支持。可访问的Annotation Processor API仅限于生成新类,并且不允许修改现有的字节码(即使在JDK8中也是如此)。您可以在注释处理器级别强制转换为编译器特定的类,这将启用更多的选项。但您必须使用编译器内部API,并为每个可用的编译器(JDT和JavaC)重写它。你可以看看龙目项目(http://projectlombok.org/)它做了一件非常相似的事情。遗憾的是,龙目尚未与JDK8的新型工作站兼容。

对于正则表达式的示例,解决方案非常简单。我还提供了一些关于解决方案不那么简单的情况的信息。

如何实现运行时测试取决于类型系统是计算数据本身的属性,还是计算来源(数据源)的属性。以下是CheckerFramework手册"运行时测试和类型细化"部分的文本:

一些类型的系统支持Checker Framework可以用于细化条件范围内的类型,例如if,在断言语句等之后

类型系统是否支持这样的运行时测试取决于类型系统是否正在计算数据本身的属性,或者物源特性(数据来源)。一个示例关于数据的属性是字符串是否为正则表达式。一关于出处的财产的例子是计量单位:无法查看数字的表示并确定它用来表示公里或英里。

1)对于数据的属性,最简单的选择是避免实例化测试,而是使用Checker Framework附带的测试,如isRegex

例如,代替

if (x instanceof @Regex String) ...

写入

if (RegexUtil.isRegex(x)) ...

你就完了。

如果你真的想使用instanceof而不是isRegex,那么你需要破解编译器,将x instanceof @Regex String的每个源代码转换为RegexUtil.isRegex(x)。您也可以通过字节码重写来实现这一点。

2) 对于出处的属性,实现工作量要大得多。您必须在程序中的每个数据(包括对象和基元)的表示中添加一个出处位,并更改每个操作(在您自己的程序和库中),以便除了对数据进行操作外,还适当地维护出处位。DynComp是一个已经做到这一点的工具,您可以在此基础上进行构建,它作为Daikon不变检测器的一部分进行分发。

最新更新