Java反射动态修改注解的值

本文探讨了如何通过Java反射动态修改注解的值。首先介绍了通常获取注解值的方式,然后展示了如何创建带有@Foo注解的Bar对象。接着,通过调试发现注解实际上是通过Proxy实现的,其内部的memberValues存储了注解属性和值。由于memberValues是私有的,因此可以使用反射修改其访问权限,进而更新注解的值。最后,提供了修改注解值的具体步骤和代码实现。
部署运行你感兴趣的模型镜像

先来看看通常情况下,我们通过反射获取注解的值的场景:

那么现在我们定义一个 @Foo 注解,它有一个类型为 String 的 value 属性,该注解应用再Field上:

/**
 * @Author 落叶飞翔的蜗牛
 * @Date 2018/3/11
 * @Description
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Foo {
    String value();
}

再定义一个普通的Java对象 Bar,它有一个私有的String属性 value,并为它设置属性值为"test.annotation.value" 的 @Foo 注解

/**
 * @Author 落叶飞翔我蜗牛
 * @Date 2018/3/11
 * @Description
 */
public class Bar {
    @Foo("test.annotation.value")
    private String value;
}

正常的获取注解属性值的场景:

/**
 * @Author 落叶飞翔的蜗牛
 * @Date 2018/3/10
 * @Description
 */
@RunWith(SpringRunner.class)
public class ReflectionAnnotationTest {

    @Test
    public void test() throws NoSuchFieldException, IllegalAccessException {
        //获取Bar实例
        Bar bar = new Bar();
        //获取Bar的val字段
        Field field = bar.getClass().getDeclaredField("value");
        //获取val字段上的Foo注解实例
        Foo foo = field.getAnnotation(Foo.class);
        //获取Foo注解实例的 value 属性值
        String value =  foo.value();
        //打印该值
        System.out.println("修改之前的注解值:" + value);

    }
}

    我们在上面的String value = foo.value(); 处下断点,我们跑一下可以发现当前栈中有这么几个变量,不过其中有一点很特别:foo,其实是个Proxy实例。


    看到foo栈中的属性h是一个AnnotationInvocationHandler类型的对象。h对象中包含一个memberValues对象,里面装着key就是我们自定义注解的属性,value就是我赋的值。我们看一下AnnotationInvocationHandler类的源码:

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;

    可以发现memberValues对象是private final修饰的。所以我们可以通过反射修改memberValues的访问权限,来打到修改memberValues值的目的。

    所以动态修改注解的值的方法为:通过反射得到foo的代理对象,然后得到代理对象的memberValues属性,修改访问权限,更新注解的value属性值。修改后的代码如下:

/**
 * @Author 落叶飞翔的蜗牛
 * @Date 2018/3/10
 * @Description
 */
@RunWith(SpringRunner.class)
public class ReflectionAnnotationTest {

    @Test
    public void test() throws NoSuchFieldException, IllegalAccessException {
        //获取Bar实例
        Bar bar = new Bar();
        //获取Bar的val字段
        Field field = bar.getClass().getDeclaredField("value");
        //获取val字段上的Foo注解实例
        Foo foo = field.getAnnotation(Foo.class);
        //获取Foo注解实例的 value 属性值
        String value =  foo.value();
        //打印该值
        System.out.println("修改之前的注解值:" + value);

        System.out.println("------------以下是修改注解的值------------");

        //获取 foo 这个代理实例所持有的 InvocationHandler
        InvocationHandler invocationHandler = Proxy.getInvocationHandler(foo);
        // 获取 AnnotationInvocationHandler 的 memberValues 字段
        Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
        // 因为这个字段事 private final 修饰,所以要打开权限
        declaredField.setAccessible(true);
        // 获取 memberValues
        Map memberValues = (Map) declaredField.get(invocationHandler);
        // 修改 value 属性值
        memberValues.put("value", "test.annotation.new.value");
        // 获取 foo 的 value 属性值
        String newValue = foo.value();
        System.out.println("修改之后的注解值:" + newValue);
    }
}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值