java - 动态修改字段注解值

标签 java reflection groovy annotations

是否可以在运行时更改字段注释值?

我可以访问这些值,但找不到更改它们的方法。

可以通过以下方式访问:

Article.class.declaredFields.find {it.name="annotatedField"}.declaredAnnotations

最佳答案

我认为除了您的字段(或对象)之外,最好保留对注释对象的引用,并在您更改其值时更新注释引用。这样,当 Class.java 中注释的实现发生变化时,您的代码不太可能出错。

answer linked in the question comments对于处理包含单个元素的注释很有用,但是如果您需要设置多个元素,这里是一个更通用的解决方案,它使用代理:

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) throws Exception {
        Foo foo = new Foo();
        Field field = foo.getClass().getDeclaredFields()[0];

        Anno anno = field.getAnnotation(Anno.class);
        System.out.println(String.format("Old properties: %s, %s, %s", anno.value(), anno.bar(), anno.barr()));

        Anno anno2 = (Anno) setAttrValue(anno, Anno.class, "value", "new");
        System.out.println(String.format("New properties: %s, %s, %s", anno2.value(), anno2.bar(), anno2.barr()));

        Anno anno3 = (Anno) setAttrValue(anno2, Anno.class, "bar", "new bar");
        System.out.println(String.format("New properties: %s, %s, %s", anno3.value(), anno3.bar(), anno3.barr())); 
    }

    public static Annotation setAttrValue(Annotation anno, Class<? extends Annotation> type, String attrName, Object newValue) throws Exception {
        InvocationHandler handler = new AnnotationInvocationHandler(anno, attrName, newValue);
        Annotation proxy = (Annotation) Proxy.newProxyInstance(anno.getClass().getClassLoader(), new Class[]{type}, handler);
        return proxy;
    }
}

class AnnotationInvocationHandler implements InvocationHandler {
    private Annotation orig;
    private String attrName;
    private Object newValue;

    public AnnotationInvocationHandler(Annotation orig, String attrName, Object newValue) throws Exception {
        this.orig = orig;
        this.attrName = attrName;
        this.newValue = newValue;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // "override" the return value for the property we want
        if (method.getName().equals(attrName) && args == null)
            return newValue;

        // keep other properties and methods we want like equals() and hashCode()
        else {
            Class<?>[] paramTypes = toClassArray(args);
            return orig.getClass().getMethod(method.getName(), paramTypes).invoke(orig, args);
        }
    }

    private static Class<?>[] toClassArray(Object[] arr) {
        if (arr == null)
            return null;
        Class<?>[] classArr = new Class[arr.length];
        for (int i=0; i<arr.length; i++)
            classArr[i] = arr[i].getClass();
        return classArr;
    }

}

class Foo {
    @Anno(value="old", bar="bar", barr="barr")
    public Object field1;
}

@Retention(RetentionPolicy.RUNTIME)
@interface Anno {
    String value();
    String bar();
    String barr();
}

程序输出:

Old properties: old, bar, barr
New properties: new, bar, barr
New properties: new, new bar, barr

关于java - 动态修改字段注解值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24367384/

相关文章:

java - 从 firebase android 检索数据

debugging - 如何在 Rust 中打印表达式及其值?

ios - 在 Objective-C 中是否有可能在运行时找到分配的对象?

eclipse - 使用 ide 编写 jenkins 控制台脚本的有效方法

java - 在没有 persistence.XML 的情况下使用 JPA 和 Spring 连接到 mysql 数据库

java - 将枚举的 ArrayList 转换为 String

使用Groovy进行JSON输出

grails - Grails 中如何覆盖外部配置文件中的配置变量,以便依赖于该变量的变量也被更新?

java - 要求输入的密码必须包含大写字母和数字?

java - 使用声明字段反射提供的方法