如何在Java中的方法参数中只允许带有特定注解的类?

huangapple go评论72阅读模式
英文:

How to allow only classes annotated with some annotation in method parameters in Java?

问题

假设我有一个注解 @MyAnnotation 和两个类:

@MyAnnotation
class Foo {
}

class Bar {
}

以及一个需要类作为参数的方法:

someMethod(Class<?> klass)

是否有可能限制 someMethod 方法的参数只能是带有 @MyAnnotation 注解的类?我的意思是:

someMethod(Foo.class) // 必须可行
someMethod(Bar.class) // 编译错误

如果可以,如何实现?

英文:

Let's suppose I have annotation @MyAnnotation and two classes:

@MyAnnotation
class Foo {
}

class Bar {
}

and some method that needs class as parameter

someMethod(Class&lt;?&gt; klass)

Is it possible to restrict someMethod parameter only to classes that are annotated with @MyAnnotation? I mean:

someMethod(Foo.class) //Must work
someMethod(Bar.class) //Compiler error

If yes, how to do that?

答案1

得分: 3

是的,这是可能的。

作为一般规则,如果使用注解来表示属性,您将需要使用注解处理器。

以下是使用Checker Framework的完整示例。

文件SO61029446.java:

public class SO61029446 {
  void someMethod(Class<? extends @MyAnnotation Object> klass) {}

  void client() {
    someMethod(Foo.class); // 必须正常工作
    someMethod(Bar.class); // 编译错误
  }
}

@MyAnnotation
@SuppressWarnings("subtyping")
class Foo {}

class Bar {}

文件MyAnnotation.java:

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf(UnknownMyAnnotation.class)
@interface MyAnnotation {}

@DefaultQualifierInHierarchy
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({})
@interface UnknownMyAnnotation {}

现在,运行这些命令(在安装了Checker Framework之后):

javacheck MyAnnotation.java
javacheck -g SO61029446.java -processor org.checkerframework.common.subtyping.SubtypingChecker -Aquals=MyAnnotation,UnknownMyAnnotation SO61029446.java

第二个命令的输出为:

SO61029446.java:11: error: [argument.type.incompatible] incompatible types in argument.
    someMethod(Bar.class); // 编译错误
                  ^
  found   : @UnknownMyAnnotation Class<@UnknownMyAnnotation Bar>
  required: @UnknownMyAnnotation Class<? extends @MyAnnotation Object>

编译器对非法调用提出了投诉,但允许了合法调用,正如您所要求的。

一些建议:

  • javacheck 命令如Checker Framework手册中所述。
  • 有两个 javacheck 命令,因为第一个命令使得注解在第二个命令的类路径上可用。
  • Foo 类上的 @SuppressWarnings("subtyping") 注解可能不需要,这取决于您的实际代码。(这只是一个示例。)
  • Slaw的答案以“不,这是不可能的。”开头,这是错误的。Slaw用不同的方法在没有使用注解的情况下解决了问题,这在某些方面是不错的(因为它仅使用Java编译器而没有额外的工具),但它并没有回答关于使用注解的问题。
英文:

Yes, this is possible.

As a general rule, if a property is expressed using an annotation, you will need to use an annotation processor.

Here is a full example that uses the Checker Framework.

File SO61029446.java:

public class SO61029446 {
  void someMethod(Class&lt;? extends @MyAnnotation Object&gt; klass) {}

  void client() {
    someMethod(Foo.class); // Must work
    someMethod(Bar.class); // Compiler error
  }
}

@MyAnnotation
@SuppressWarnings(&quot;subtyping&quot;)
class Foo {}

class Bar {}

File MyAnnotation.java:

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf(UnknownMyAnnotation.class)
@interface MyAnnotation {}

@DefaultQualifierInHierarchy
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({})
@interface UnknownMyAnnotation {}

Now, run these commands (after installing the Checker Framework):

javacheck MyAnnotation.java
javacheck -g SO61029446.java -processor org.checkerframework.common.subtyping.SubtypingChecker -Aquals=MyAnnotation,UnknownMyAnnotation SO61029446.java

The output of the second command is:

SO61029446.java:11: error: [argument.type.incompatible] incompatible types in argument.
    someMethod(Bar.class); // Compiler error
                  ^
  found   : @UnknownMyAnnotation Class&lt;@UnknownMyAnnotation Bar&gt;
  required: @UnknownMyAnnotation Class&lt;? extends @MyAnnotation Object&gt;

The compiler has complained about the illegal invocation but has permitted the legal invocation, just as you requested.

A few notes:

  • The javacheck command is as described in the Checker Framework Manual.
  • There are two javacheck commands because the first one makes the annotations available on the classpath for the second one.
  • The @SuppressWarnings(&quot;subtyping&quot;) annotation on the Foo class might not be needed, depending on your actual code. (This is a toy example.)
  • Slaw's answer starts with first sentence "No, this is not possible.", which is incorrect. Slaw's different approach to solving the problem without annotations is not a bad one (in some ways it's better because it uses just the Java compiler without any additional tool), but it does not answer this question about using annotations.

huangapple
  • 本文由 发表于 2020年4月4日 22:16:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/61029446.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定