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 List DIALECTS =
+ 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));
+ }
}