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

我可以使用Java注释来定义编译时检查吗?,java,eclipse,eclipse-plugin,annotations,compiler-options,Java,Eclipse,Eclipse Plugin,Annotations,Compiler Options,例如,我想创建注释@Out to target参数。然后,我会以某种方式使用编译器来检查参数值是否在函数返回之前设置好。这可能吗 还考虑了一个@Immutable注释,它不允许调用任何未用@Const注释的方法,也不允许访问任何公共字段。(编译时,可能是运行时?) 到目前为止,我有: //I'm assuming Class retention is a subset of Runtime retention @Retention(RetentionPolicy.RUNTIME) @Target

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

还考虑了一个@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
{

}
我想我可以开始设计一种策略,在运行时使用反射来实现它,但我想指示编译器或预处理器替我检查这些东西,这样我的注释就不会有任何开销

这是你认为“如果可以做到的话,它已经在那里了,如果是的话,我在哪里可以抓住它”

编辑:在进一步思考了
@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, i.e., 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中


javac编译器支持用户定义的插件,称为注释处理器,可以完全实现您想要的功能。您可以将注释视为语言扩展

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

一个易于编写此类注释处理器的框架是,它包含注释的定义,如
@NonNull
@Immutable
。以下是关于如何使用Checker框架验证代码的两个教程:

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


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

说真的,我认为要想做您想做的事情,您需要一个支持用户定义插件的编译器。我不知道还有什么。从编译器编写者的角度来看,这听起来很难提供。@ajb这令人失望。注释应该用作语言扩展。我可能会构建类似于编译器的东西。预编译器,pehaps?您可以定义注释处理器。注释的保留将是
SOURCE
。然后,通过在
META-INF/services/javax.annotation.processing.processor
中定义处理器impl的完全限定名,创建一个并将其附加到项目中。您还必须启用注释处理。缺点是,您必须在错误/警告出现之前保存文件,而不是像内置编译时检查一样立即出现。这篇博文描述了ProjectLombok如何与编译过程挂钩:我将以这种方式实现它。谢谢你的帮助。我不喜欢checker框架,因为它速度慢而且不完整。您需要多个“检查器”来定义不变性。一旦它准备好了,我会发表,谁知道呢,也许有人会发现它很有用。听起来很棒。请分享你的结果。