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

时间:2012-09-24 21:12:31

标签: java annotations code-generation bytecode-manipulation annotation-processing

JSR 308建议在Java中添加类型注释。在批准之后,程序员将能够在当前允许Java类型的任何地方添加注释。这不仅包括方法/字段/本地/参数装饰,还包括构造函数调用,类型转换以及最奇怪的实例检查。 Checker Framework使用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有关吗?

2 个答案:

答案 0 :(得分:5)

是的,你可以。但它不是微不足道的,并且不受注释处理器可访问API的支持。可访问的注释处理器API仅限于生成新类,不允许修改现有的字节码(即使在JDK 8中)。您可以在注释处理器级别转换为编译器特定的类,这样可以提供更多选项。但您必须使用编译器内部API并为每个可用的编译器(JDT和JavaC)重写它。您可以看一下Lombok(http://projectlombok.org/)项目,该项目的功能非常相似。可悲的是,龙目岛尚未与JDK8s新型的anntotations兼容。

答案 1 :(得分:2)

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

如何实现运行时测试取决于类型系统是计算数据本身的属性还是来源属性(数据源)。以下是Run-time tests and type refinement

中“Checker Framework manual”部分的文字
  

某些类型系统支持Checker Framework的运行时测试   可用于在条件范围内细化类型,例如if,   在断言后等等。

     

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

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

例如,而不是

  if (x instanceof @Regex String) ...

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

你已经完成了。

如果您确实想使用instanceof而不是isRegex,那么您需要破解编译器,将x instanceof @Regex String的每个源代码事件转换为RegexUtil.isRegex(x)。您也可以通过字节码重写来完成此操作。

2)对于来源的属性,实施工作量要大得多。您必须在程序中的每个数据的表示中添加起源位(包括对象和基元)并更改每个操作(在您自己的程序和库中),这样除了对数据进行操作外,它还适当保持原产地位。已经执行此操作的工具DynCompDaikon invariant detector,它是{{3}}的一部分。