更改Java 8中字段注释的注释值



我认为标题描述了问题。下面是一些代码:

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层重新读取的。在这些副本中,您可以更改值,但如果重新加载,这些值就会消失。

是我错过了什么,还是真的不可能?

注释是修饰符就像privatesynchronized一样。它们是类的不变静态结构的一部分,不打算被修改。您可以侵入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();
}

相关内容

  • 没有找到相关文章

最新更新