动态修改字段注释值

时间:2014-06-23 13:36:27

标签: java reflection groovy annotations

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

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

可以通过以下方式进行访问:

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

1 个答案:

答案 0 :(得分:6)

我认为除了Field(或Object)之外,最好保持对Annotation对象的引用,并在更改其值时更新Annotation引用。这样,当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