4

JSR 308建议向 Java 添加类型注释。批准后,程序员将能够在当前允许 Java 类型的任何地方添加注释。这不仅包括方法/字段/本地/参数装饰,还包括构造函数调用、类型转换和最奇怪的 instanceof 检查。Checker 框架使用JSR 308 来实现类型限定符@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可以做到这一点吗?

4

2 回答 2

5

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

于 2012-10-01T07:39:54.957 回答
2

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

如何实现运行时测试取决于类型系统是计算数据本身的属性,还是计算出处(数据源)的属性。以下是Checker Framework 手册的“运行时测试和类型改进”部分的文本:

某些类型系统支持运行时测试,Checker 框架可以使用该测试来细化条件范围内的类型,例如 if、assert 语句之后等。

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

1) 对于data的属性,您最简单的选择是避免使用 instanceof 测试,而是使用 Checker Framework 附带的测试,例如isRegex.

例如,而不是

  if (x instanceof @Regex String) ...

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

你就完成了。

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

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

于 2014-09-30T08:03:36.433 回答