当前位置: 首页 > 知识库问答 >
问题:

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

有凯泽
2023-03-14

例如,我想创建注释@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和访问方法和字段。然后我做了一堆我的插件应该检测到的虚拟注释,然后我试图打印结果,但我甚至不确定会发生什么。我的插件是一个“增量构建”插件。这是它的代码,如果有人能看看并向我解释一些事情。我完全迷失在这个应用编程接口中。

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

共有1个答案

印瑾瑜
2023-03-14

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

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

一个使编写这种注释处理器变得容易的框架是Checker框架,它包含注释的定义,如@NonNull@Immutable。这里有两个关于如何使用Checker框架验证代码的教程:教程1,教程2。

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

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

 类似资料:
  • 问题内容: 我想知道是否有一种方法可以指定在类方法之前调用方法。我知道这样的事情应该是可能的,因为JUnit具有before(),所以我想做的事情是相似的。 这是我想做的一个具体例子 基本上我想要一个注释在foo()之前告诉编译器或jvm调用init() 问题答案: 如果有的话,您可以使用此接口的实例和方法的内部包装,您可以自由检查方法是否带注释,并根据该方法执行一些操作: 或者,您可以尝试使用A

  • 问题内容: 我有一个要求,根据字段上标记的自定义注释来编组/解组java pojo的某些元素。假设我的Java pojp中有3个字段 如果我在jaxb中进行转换时传递version =“ v1”参数,我只想编组具有v1的字段。如果我通过v2,则所有带v2注释的字段都应编组。 甚至可以使用jaxb吗?我确信选择性的编组将通过某种图书馆或某种方式得到支持,经过大量的搜索后仍无法弄清楚。任何帮助或建议或

  • 我正在编写一个注释处理器来在编译时执行以下检查: 有一个接口 有一个注释<code>Apply<code>用于注释方法 用注释的方法应被称为,并且只取实现 到目前为止,我已经识别了所有名为< code>apply的带注释的方法,并提取了它们作为参数的类名。所以我只剩下: 问题是:如果有的话,我如何才能从中获得参数的类层次结构表示,以便检查它是否实现了。无法使用<code>类加载器。loadClas

  • 问题内容: 我想将通用映射分组到中,但不能使用,因为我的实体已经扩展了另一个。所以我需要一个类似下面的界面: 我想像下面这样使用它: 我的意思是说这项工作可行吗? 我可以在接口上使用@MappedSuperclass注释吗? Hibernate是否支持接口? 问题答案: 号如前所述这里: JPA不直接支持接口或变量关系。

  • 问题内容: 我是JAX-RS的新手,我试图了解注释的工作方式。 在javadoc中有六个等级的列表()。但是,我在网络上找到将this注释与其他类型一起使用的代码,例如: 是否有可以与此注释一起使用的受支持类型的列表?在执行标准之间,此列表是否会更改? 我目前正在试验Jersey,我担心自己写的代码无法移植到其他JAX-RS实现中。 问题答案: 铆接的JAX-RS 规范定义了你可以通过注入的所有标

  • 我是 JAX-RS 的新手,我正在尝试了解注释应该如何工作。 在javadoc中有一个包含六个类的列表(< code >应用程序、< code>UriInfo、< code >请求、< code>HttpHeaders、< code >安全上下文、< code >提供者)。但是,我在网上找到了将this批注用于其他类型的代码,例如: 是否有可用于此批注的支持类型列表?该列表在标准实施期间是否发生变