diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
index 5a81bb816..d56e01966 100755
--- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
@@ -9,6 +9,7 @@ import cn.hutool.core.exceptions.InvocationTargetRuntimeException;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Filter;
+import java.lang.reflect.Modifier;
import cn.hutool.core.lang.reflect.MethodHandleUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
@@ -303,6 +304,7 @@ public class ReflectUtil {
* 设置字段值
* 若值类型与字段类型不一致,则会尝试通过 {@link Convert} 进行转换
* 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})
+ * 如果是final字段,setFieldValue,调用这可以先调用 {@link ReflectUtil#removeFinalModify(Field)}方法去除final修饰符
*
* @param obj 对象,static字段则此处传Class
* @param fieldName 字段名
@@ -321,7 +323,8 @@ public class ReflectUtil {
/**
* 设置字段值
* 若值类型与字段类型不一致,则会尝试通过 {@link Convert} 进行转换
- * 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})
+ * 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})
+ * 如果是final字段,setFieldValue,调用这可以先调用 {@link ReflectUtil#removeFinalModify(Field)}方法去除final修饰符
*
* @param obj 对象,如果是static字段,此参数为null
* @param field 字段
@@ -1108,6 +1111,58 @@ public class ReflectUtil {
return accessibleObject;
}
+ /**
+ * 设置final的field字段可以被修改
+ *
+ * 只要不会被编译器内联优化的 final 属性就可以通过反射有效的进行修改 -- 修改后代码中可使用到新的值;
+ *
+ *
+ * //示例,移除final修饰符
+ * class JdbcDialects {private static final List dialects = new ArrayList<>();}
+ * Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
+ * ReflectUtil.removeFinalModify(field);
+ * ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);
+ *
+ * @param field 被修改的field,不可以为空
+ * @throws UtilException IllegalAccessException等异常包装
+ * @since 5.8.8
+ * @author dazer
+ */
+ public static void removeFinalModify(Field field) {
+ if (field != null) {
+ if (ModifierUtil.hasModifier(field, ModifierUtil.ModifierType.FINAL)) {
+ //将字段的访问权限设为true:即去除private修饰符的影响
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ try {
+ //去除final修饰符的影响,将字段设为可修改的
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ //Field 的 modifiers 是私有的
+ modifiersField.setAccessible(true);
+ //& :位与运算符,按位与; 运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
+ //~ :位非运算符,按位取反;运算规则:转成二进制,如果位为0,结果是1,如果位为1,结果是0.
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ //内部,工具类,基本不抛出异常
+ throw new UtilException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName());
+ }
+ }
+ }
+ }
+
/**
* 获取方法的唯一键,结构为:
* diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java index 7792804a8..6170ec61b 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java @@ -13,7 +13,9 @@ import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.Map; /** @@ -268,4 +270,26 @@ public class ReflectUtilTest { int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class); Assert.assertArrayEquals(new int[0], intArray); } + + public static class JdbcDialects { + private static final ListDIALECTS = + Arrays.asList(1L, 2L, 3L); + } + + @Test + public void setFieldValueTest() { + String fieldName = "DIALECTS"; + final List dialects = + Arrays.asList( + 1, + 2, + 3, + 99 + ); + Field field = ReflectUtil.getField(JdbcDialects.class, fieldName); + ReflectUtil.removeFinalModify(field); + ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects); + + Assert.assertEquals(dialects, ReflectUtil.getFieldValue(JdbcDialects.class, fieldName)); + } }