28

我想为一些方法生成的一些值提供注释。

到目前为止我试过这个:

public @interface MyInterface {
    String aString();
}

@MyInterface(aString = MyClass.GENERIC_GENERATED_NAME)
public class MyClass {

    static final String GENERIC_GENERATED_NAME = MyClass.generateName(MyClass.class);

    public static final String generateName(final Class<?> c) {
        return c.getClass().getName();
    }
}

想法GENERIC_GENERATED_NAMEstatic final,它抱怨说

注释属性的值MyInterface.aString必须是常量表达式

那么如何实现呢?

4

3 回答 3

28

无法动态生成注释中使用的字符串。编译器在编译时评估注解的注解元数据RetentionPolicy.RUNTIME,但GENERIC_GENERATED_NAME直到运行时才知道。并且您不能将生成的值用于注释,RetentionPolicy.SOURCE因为它们在编译时被丢弃,因此这些生成的值永远不会被知道。

于 2012-05-17T13:06:49.460 回答
9

解决方案是改用带注释的方法。调用该方法(使用反射)以获取动态值。

从用户的角度来看,我们有:

@MyInterface
public class MyClass {
    @MyName
    public String generateName() {
        return MyClass.class.getName();
    }
}

注释本身将被定义为

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface @MyName {
}

实现对这两个注释的查找非常简单。

// as looked up by @MyInterface
Class<?> clazz;

Method[] methods = clazz.getDeclaredMethods();
if (methods.length != 1) {
    // error
}
Method method = methods[0];
if (!method.isAnnotationPresent(MyName.class)) {
    // error as well
}
// This works if the class has a public empty constructor
// (otherwise, get constructor & use setAccessible(true))
Object instance = clazz.newInstance();
// the dynamic value is here:
String name = (String) method.invoke(instance);
于 2014-08-12T00:20:31.053 回答
5

没有办法像其他人所说的那样动态地修改注释的属性。不过,如果您想实现这一目标,有两种方法可以做到这一点。

  1. 将表达式分配给注释中的属性,并在检索注释时处理该表达式。在您的情况下,您的注释可以是

    @MyInterface(aString = "objectA.doSomething(args1, args2)")

当您阅读时,您可以处理字符串并进行方法调用并检索值。Spring 通过 SPEL(Spring 表达式语言)来做到这一点。这是资源密集型的,每次我们想要处理表达式时都会浪费 cpu 周期。如果您使用的是 spring,您可以挂接一个 beanPostProcessor 并处理一次表达式并将结果存储在某处。(可以是全局属性对象,也可以是可以在任何地方检索的地图)。

  1. 这是做我们想做的事的一种骇人听闻的方式。Java 存储了一个私有变量,该变量维护类/字段/方法上的注释映射。您可以使用反射并获取该地图。因此,在第一次处理注释时,我们解析表达式并找到实际值。然后我们创建所需类型的注释对象。我们可以将新创建​​的带有实际值(常量)的注解放在注解的属性上,并覆盖检索到的地图中的实际注解。

jdk 存储注解映射的方式取决于 java 版本并且不可靠,因为它没有公开使用(它是私有的)。

您可以在此处找到参考实现。

https://rationaleemotions.wordpress.com/2016/05/27/changeing-annotation-values-at-runtime/

PS:我还没有尝试和测试过第二种方法。

于 2017-01-21T15:21:28.660 回答