Java Annotations值以动态方式提供

时间:2012-05-17 12:59:35

标签: java annotations

我想提供带有某些方法生成的某些值的注释。

到目前为止我试过这个:

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的值必须是常量表达式

那么如何实现这个目标呢?

3 个答案:

答案 0 :(得分:19)

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

答案 1 :(得分:6)

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

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

@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);

答案 2 :(得分:0)

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

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

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

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

    1. 这是一种做我们想要的事情的hacky方式。 Java存储一个私有变量,该变量维护类/字段/方法上的注释映射。您可以使用反射并获取该地图。因此,在第一次处理注释时,我们解析表达式并找到实际值。然后我们创建所需类型的注释对象。我们可以将新创建​​的注释与实际值(常量)放在注释的属性上,并覆盖检索到的地图中的实际注释。
    2. jdk存储注释图的方式是依赖于Java版本的,并且不可靠,因为它没有公开使用(它是私有的)。

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

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

      P.S:我没有尝试过第二种测试方法。