我认为标题描述了问题。下面是一些代码:
import static org.junit.Assert.assertEquals;
import java.lang.annotation.*;
public class Main {
public static void main(String[] args) throws Exception {
assertEquals("foo", Main.class.getDeclaredMethod("myMethod").getAnnotation(Anno.class).param());
// the magic here -> set to bar
assertEquals("bar", Main.class.getDeclaredMethod("myMethod").getAnnotation(Anno.class).param());
}
@Anno(param = "foo")
public void myMethod() {}
@Retention(RetentionPolicy.RUNTIME)
@interface Anno {
String param();
}
}
到目前为止,我猜这是不可能的。似乎总是当你试图通过反射获得方法时,你只会得到副本,所有的值(如注释)都是从更深的java层重新读取的。在这些副本中,您可以更改值,但如果重新加载,这些值就会消失。
是我错过了什么,还是真的不可能?
注释是修饰符就像private
或synchronized
一样。它们是类的不变静态结构的一部分,不打算被修改。您可以侵入Reflection实现以使特定方法打印您想要的内容,但是除了这种侵入的肮脏之外,您根本没有更改注释,您只是侵入了特定库的数据结构。
还有其他反射或字节码操作库,它们不会使用内置反射API,而是直接读取字节码(例如通过getResource()
或通过Instrumentation API)。这些库永远不会注意到你的操作。
换句话说,如果你想将可变数据与一个方法关联起来,不要使用注释。您可以简单地使用Map<Method,MutableData>
,或者,如果您只有一个特定的方法,则声明一个良好的旧static
字段,该字段已经提供了您需要的所有功能,并且更容易处理。
我发布了一个在Java 8之前做同样任务的链接。在Java 8(1.8.0_51)中似乎可以做同样的事情。整个测试设置
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class Test {
public static void main(String... args) {
Test t = new Test();
t.check();
Test.change();
t.check();
new Test().check();
}
public Test() {
}
public static void change() {
try {
Method m = Test.class.getMethod("myMethod");
// The map has to be built for the first time
m.getDeclaredAnnotations();
Class<?> superclass = m.getClass().getSuperclass();
Field declaredField = superclass.getDeclaredField("declaredAnnotations");
declaredField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<Class<? extends Annotation>, Annotation> map = (Map<Class<? extends Annotation>, Annotation>) declaredField
.get(m);
map.put(Anno.class, new Anno() {
@Override
public Class<? extends Annotation> annotationType() {
return Anno.class;
}
@Override
public String param() {
return "new";
}
});
} catch (SecurityException | NoSuchMethodException | IllegalArgumentException | NoSuchFieldException
| IllegalAccessException e) {
e.printStackTrace();
}
}
public void check() {
try {
System.out.println(getClass().getMethod("myMethod").getAnnotation(Anno.class).param());
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
@Anno(param = "test")
public void myMethod() {
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Anno {
String param();
}