我可以使用Java注释来定义编译时间检查吗?

例如,我想创建注释@Out来定位参数。 然后我会以某种方式使用编译器来检查函数返回之前是否设置了参数值。 这可能吗?

还考虑了一个@Immutable注释,该注释不允许调用任何未使用@Const注释的方法或访问任何公共字段。 (编译时间,可能是运行时?)

到目前为止我有这个:

//I'm assuming Class retention is a subset of Runtime retention @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Out { //no idea what to go in here. } 

这是另一个注释。 再次,我没有完整的定义:

 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Immutable { } 

我想我可以开始设计一个策略来在运行时使用reflection实现它,但我想指示编译器或预处理器为我检查那些东西,所以我的注释将没有开销。

这是你认为“如果可以做到这一点,它已经在那里,如果是,我可以在哪里抓住它”的事情之一。

编辑 :在进一步考虑@Const@Immutable之后,在记住java通过值传递指向对象的指针之后,我扩展了@Const的定义,摆脱了@Immutable ,并改变了@Out的定义,如下所示:

 /** * When Applied to a method, ensures the method doesn't change in any * way the state of the object used to invoke it, ie, all the fields * of the object must remain the same, and no field may be returned, * unless the field itself is marked as {@code @Const}. A method * annotated with {@code @Const} can only invoke other {@code @Const} * methods of its class, can only use the class's fields to invoke * {@code @Const} methods of the fields classes and can only pass fields * as parameters to methods that annotate that formal parameter as * {@code @Const}. * * When applied to a formal parameter, ensures the method will not * modify the value referenced by the formal parameter. A formal * parameter annotated as {@code @Const} will not be aliased inside the * body of the method. The method is not allowed to invoke another * method and pass the annotated parameter, save if the other method * also annotates the formal parameter as {@code @Const}. The method is * not allowed to use the parameter to invoke any of its type's methods, * unless the method being invoked is also annotated as {@code @Const} * * When applied to a field, ensures the field cannot be aliased and that * no code can alter the state of that field, either from inside the * class that owns the field or from outside it. Any constructor in any * derived class is allowed to set the value of the field and invoke any * methods using it. As for methods, only those annotated as * {@code @Const} may be invoked using the field. The field may only be * passed as a parameter to a method if the method annotates the * corresponding formal parameter as {@code @Const} * * When applied to a local variable, ensures neither the block where the * variable is declared or any nested block will alter the value of that * local variable. The local variable may be defined only once, at any * point where it is in scope. Only methods annotated as * {@code @Const} may be invoked using this variable, and the variable * may only be passed as a parameter to another method if said method * annotates its corresponding formal parameter as {@code @Const} * */ @Retention(RetentionPolicy.SOURCE) @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Inherited public @interface Const { } 

现在@Out

 /** * The formal parameter annotated with {@code @Out} must be undefined in * the scope of the caller, and it's the responsibility of the method to * define it. If allowNull is true, the parameter can be explicitly set * to null in the body of the method. */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.PARAMETER) public @interface Out { boolean allowNull() default false; } 

编辑:我正在尝试将其作为eclipse插件实现,但我完全忘记了阅读手册。 我写了一个插件,其中包含访问AST和访问方法和字段的基本逻辑。 然后我做了一堆我的插件应该检测到的虚拟注释,然后我尝试打印结果,但我甚至不确定会发生什么。 我的插件是一个“增量构建”插件。 这是代码,如果有人可以看看,只是向我解释一些事情。 我完全迷失在这个API中。

https://github.com/Starless2001/Plugin-for-Eclipse

javac编译器支持用户可定义的插件,称为注释处理器,可以完全满足您的需求。 您可以将注释视为语言扩展。

定义public @interface Immutable { ... }定义语法:您可以在程序中编写的@Immutable注释。 注释处理器(编译器插件)定义语义:它强制执行语义规则,并在程序违反规则时发出编译器警告。

一个可以轻松编写此类注释处理器的框架是Checker Framework ,它包含@NonNull@Immutable等注释的定义。 以下是有关如何使用Checker Frameworkvalidation代码的两个教程: 教程1 , 教程2 。

在每个声明上调用普通的Java注释处理,例如类,字段,方法和方法参数,普通Java使注释处理器无法访问程序的完整AST。 您可以将Checker Framework视为一个扩展Java注释处理function的库。 它使您可以访问每个类的完整AST,并允许您为程序中的每个语句定义规则。 因此,当语句在@Immutable对象上调用非@Const方法时,注释处理器可以发出警告。

您的注释处理器应该是模块化的,一次只能处理一个类。 注释处理器可以访问当前类的AST,以及它使用的所有类的签名,包括注释。 注释处理为您提供该信息(但不是一次性提供给整个项目的AST)。