如何在java17中动态修改注解值

前提

项目开始使用springboot3了,所以java的版本也升级了,用的是java17,该版本是一个长期维护的版本,所以没有用java19

版本差异介绍

从 Java 9 开始,setAccessible() 方法被标记为 @Deprecated,并且引入了模块化系统

//java9代码
//代码从chatgpt获取,如果不对请留言提供一下代码
@Deprecated(since="9")
public final void setAccessible(boolean flag) throws SecurityException {
    if (flag == accessible) {  // 判断是否和当前权限状态一致
        return;
    }
    if (flag) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkPermission(accessPermission);
        }
    }
    checkPermissionFromStack();  // 检查权限
    accessible = flag;
}

java11开始,因为安全问题,部分包,类已经不可以被反射并设置值,反射需要在java启动的时候添加相应的命令,例如
–add-opens java.base/java.lang=ALL-UNNAMED
–add-opens java.base/java.lang.reflect=ALL-UNNAMED

//java17代码
@Override
@CallerSensitive
public void setAccessible(boolean flag) {
    AccessibleObject.checkPermission();
    if (flag) checkCanSetAccessible(Reflection.getCallerClass());
    setAccessible0(flag);
}
java11 setAccessible方法说明

上述代码最终调用的是AccessibleObjectcheckCanSetAccessible方法,该方法会做一些列的判断,例如

  • 调用类和Field中声明的类是否是同一个
  • 是否是Object类
  • private是否是在一个类中
  • protected是否在同一个包下
  • 被调用类是否是final修饰的
  • Field中声明的类是否是final修饰的
  • Field中声明的类是否不是命名的
  • Field中生命的类所在的包是否被排除
  • 被反射的类是否对调用的类的开放

暂时试出来的被修饰后不可以反射的有被保护的包,final修饰的类/字段/方法,volatile,native,transient,其他的暂时不清楚

如何用代码的方式对被保护的类进行反射呢?

暂时的答案是做不到
这个是其他人写的,我按照这个方式是不可以的

一种适用于 Java 8 至 Java 17 的反射修改 static final 属性的方法

解决方案
上代码
下边的代码可以在java8中可以使用
如果需要在java17使用,需要添加其他参数,继续往下看
@SneakyThrows
public static <T extends Annotation> void setValueToAnnotate(T annotation, String valueName, Object value) {
	InvocationHandler invocationHandler = null;
	if (Objects.nonNull(annotation)) {
		invocationHandler = Proxy.getInvocationHandler(annotation);
	}
	if (Objects.isNull(invocationHandler)) {
		return;
	}
	Field nameField = invocationHandler.getClass().getDeclaredField("memberValues");
	nameField.setAccessible(true);
	Map<String, Object> memberValues = (Map<String, Object>) nameField.get(invocationHandler);
	memberValues.put(valueName, value);
}

在java17中,需要在java命令后边添加启动参数

–add-opens java.base/sun.reflect.annotation=ALL-UNNAMED

  • –add-opens 允许指定的模块下的包可以被其他模块以反射的方式访问
  • java.base是模块名,也代表了java核心库模块
  • sun.reflect.annotation 是一个要打开访问权限的包路径
  • ALL-UNNAMED 是一个表示所有模块的未命名模块的特殊标识。

如果要在idea中使用,需要再Run/Debug Configurations界面中添加信息

在这里插入图片描述

点击Modify options

在这里插入图片描述

选择Add VM options
复制命令到文本框中,启动项目即可

引用文章:
可参考文章:
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值