mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
!810 反射新增:setFieldModify(field)方法,设置final字段可以被修改,并设置到:setFieldValue中
Merge pull request !810 from dazer007/v5-dev-ReflectUtil-add-setFieldModify
This commit is contained in:
commit
0941210553
@ -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 {
|
||||
* 设置字段值<br>
|
||||
* 若值类型与字段类型不一致,则会尝试通过 {@link Convert} 进行转换<br>
|
||||
* 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})
|
||||
* 如果是final字段,setFieldValue,调用这可以先调用 {@link ReflectUtil#removeFinalModify(Field)}方法去除final修饰符<br>
|
||||
*
|
||||
* @param obj 对象,static字段则此处传Class
|
||||
* @param fieldName 字段名
|
||||
@ -321,7 +323,8 @@ public class ReflectUtil {
|
||||
/**
|
||||
* 设置字段值<br>
|
||||
* 若值类型与字段类型不一致,则会尝试通过 {@link Convert} 进行转换<br>
|
||||
* 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})
|
||||
* 若字段类型是原始类型而传入的值是 null,则会将字段设置为对应原始类型的默认值(见 {@link ClassUtil#getDefaultValue(Class)})<br>
|
||||
* 如果是final字段,setFieldValue,调用这可以先调用 {@link ReflectUtil#removeFinalModify(Field)}方法去除final修饰符
|
||||
*
|
||||
* @param obj 对象,如果是static字段,此参数为null
|
||||
* @param field 字段
|
||||
@ -1108,6 +1111,58 @@ public class ReflectUtil {
|
||||
return accessibleObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置final的field字段可以被修改
|
||||
* <p>
|
||||
* 只要不会被编译器内联优化的 final 属性就可以通过反射有效的进行修改 -- 修改后代码中可使用到新的值;
|
||||
* <br/>
|
||||
* <h3>以下属性,编译器会内联优化,无法通过反射修改:</h3>
|
||||
* <ul>
|
||||
* <li> 基本类型 byte, char, short, int, long, float, double, boolean</li>
|
||||
* <li> Literal String 类型(直接双引号字符串)</li>
|
||||
* </ul>
|
||||
* <h3>以下属性,可以通过反射修改:</h3>
|
||||
* <ul>
|
||||
* <li>基本类型的包装类 Byte、Character、Short、Long、Float、Double、Boolean</li>
|
||||
* <li>字符串,通过 new String("")实例化</li>
|
||||
* <li>自定义java类</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <code>
|
||||
* //示例,移除final修饰符
|
||||
* class JdbcDialects {private static final List<Number> dialects = new ArrayList<>();}
|
||||
* Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
|
||||
* ReflectUtil.removeFinalModify(field);
|
||||
* ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);
|
||||
* </code>
|
||||
* @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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方法的唯一键,结构为:
|
||||
* <pre>
|
||||
|
@ -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<Number> DIALECTS =
|
||||
Arrays.asList(1L, 2L, 3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setFieldValueTest() {
|
||||
String fieldName = "DIALECTS";
|
||||
final List<Number> 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));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user