ModifierUtil和ReflectUtil增加removeFinalModify

This commit is contained in:
Looly 2022-09-21 18:31:31 +08:00
parent 0941210553
commit eef7943d8a
4 changed files with 71 additions and 36 deletions

View File

@ -3,12 +3,13 @@
-------------------------------------------------------------------------------------------------------------
# 5.8.8.M1 (2022-09-20)
# 5.8.8.M1 (2022-09-21)
### 🐣新特性
* 【core 】 StreamUtil.of方法新增对 Iterator 支持StreamUtil.of(Iterable) 方法优化pr#807@Gitee
* 【core 】 增加.wgt格式的MimeTypepr#2617@Github
* 【core 】 EnumUtil.getBy增加带默认值重载issue#I5RZU6@Gitee
* 【core 】 ModifierUtil和ReflectUtil增加removeFinalModifypr#810@Gitee
### 🐞Bug修复
* 【core 】 修复FileNameUtil.cleanInvalid无法去除换行符问题issue#I5RMZV@Gitee

View File

@ -1,5 +1,7 @@
package cn.hutool.core.util;
import cn.hutool.core.exceptions.UtilException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -262,6 +264,58 @@ public class ModifierUtil {
public static boolean isAbstract(Method method) {
return hasModifier(method, ModifierType.ABSTRACT);
}
/**
* 设置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>基本类型的包装类 ByteCharacterShortLongFloatDoubleBoolean</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 (hasModifier(field, ModifierUtil.ModifierType.FINAL)) {
//将字段的访问权限设为true即去除private修饰符的影响
if (false == field.isAccessible()) {
field.setAccessible(true);
}
try {
//去除final修饰符的影响将字段设为可修改的
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 (final NoSuchFieldException | IllegalAccessException e) {
//内部工具类基本不抛出异常
throw new UtilException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName());
}
}
}
}
//-------------------------------------------------------------------------------------------------------- Private method start
/**

View File

@ -9,7 +9,6 @@ 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;
@ -1141,26 +1140,7 @@ public class ReflectUtil {
* @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());
}
}
}
ModifierUtil.removeFinalModify(field);
}
/**

View File

@ -74,7 +74,7 @@ public class ReflectUtilTest {
@Test
public void getFieldTest() {
// 能够获取到父类字段
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
final Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
Assert.assertNotNull(privateField);
}
@ -87,14 +87,14 @@ public class ReflectUtilTest {
@Test
public void setFieldTest() {
TestClass testClass = new TestClass();
final TestClass testClass = new TestClass();
ReflectUtil.setFieldValue(testClass, "a", "111");
Assert.assertEquals(111, testClass.getA());
}
@Test
public void invokeTest() {
TestClass testClass = new TestClass();
final TestClass testClass = new TestClass();
ReflectUtil.invoke(testClass, "setA", 10);
Assert.assertEquals(10, testClass.getA());
}
@ -155,7 +155,7 @@ public class ReflectUtilTest {
private String n;
}
public static Method getMethodWithReturnTypeCheck(Class<?> clazz, boolean ignoreCase, String methodName, Class<?>... paramTypes) throws SecurityException {
public static Method getMethodWithReturnTypeCheck(final Class<?> clazz, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
}
@ -163,7 +163,7 @@ public class ReflectUtilTest {
Method res = null;
final Method[] methods = ReflectUtil.getMethods(clazz);
if (ArrayUtil.isNotEmpty(methods)) {
for (Method method : methods) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
&& (res == null
@ -252,22 +252,22 @@ public class ReflectUtilTest {
@Test
public void newInstanceIfPossibleTest(){
//noinspection ConstantConditions
int intValue = ReflectUtil.newInstanceIfPossible(int.class);
final int intValue = ReflectUtil.newInstanceIfPossible(int.class);
Assert.assertEquals(0, intValue);
Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
final Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
Assert.assertEquals(new Integer(0), integer);
Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
final Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
Assert.assertNotNull(map);
Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
final Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
Assert.assertNotNull(collection);
Week week = ReflectUtil.newInstanceIfPossible(Week.class);
final Week week = ReflectUtil.newInstanceIfPossible(Week.class);
Assert.assertEquals(Week.SUNDAY, week);
int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
final int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
Assert.assertArrayEquals(new int[0], intArray);
}
@ -277,8 +277,8 @@ public class ReflectUtilTest {
}
@Test
public void setFieldValueTest() {
String fieldName = "DIALECTS";
public void setFieldValueWithFinalTest() {
final String fieldName = "DIALECTS";
final List<Number> dialects =
Arrays.asList(
1,
@ -286,7 +286,7 @@ public class ReflectUtilTest {
3,
99
);
Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
final Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
ReflectUtil.removeFinalModify(field);
ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);