Java注释值以dynamic方式提供

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

我到目前为止尝试过:

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

那么如何实现呢?

没有办法dynamic生成注释中使用的string。 编译器在编译时评估注释元数据的RetentionPolicy.RUNTIME注释,但直到运行时GENERIC_GENERATED_NAME才知道。 而且,您不能使用生成的值作为RetentionPolicy.SOURCE注释,因为它们在编译时被丢弃,所以这些生成的值永远不会被知道。

解决方法是使用注释的方法。 调用该方法(带reflection)来获取dynamic值。

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

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

没有办法象别人说的那样dynamic地修改注解的属性。 如果你想达到这个目的,有两种方法可以做到这一点。

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

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

当你读到的时候,你可以处理string,并调用方法并检索值。 Spring通过SPEL(Springexpression式语言)来实现这一点。 这是资源密集型的,每当我们想要处理这个expression式的时候,CPU周期就会被浪费掉。 如果你正在使用spring,你可以挂接一个beanPostProcessor,并处理一次expression式并将结果存储在某个地方。 (全局属性对象或可以在任何地方检索的地图)。

  1. 这是做我们想要的一个黑客的方式。 Java存储一个私有variables,它在类/字段/方法上维护一个注解映射。 您可以使用reflection并获取该地图。 所以在第一次处理注释时,我们parsingexpression式并find实际的值。 然后我们创build一个所需types的注释对象。 我们可以将新创build​​的注解与注释属性上的实际值(常量)进行比较,并覆盖检索的地图中的实际注释。

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

你可以在这里find一个参考实现。

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

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