mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
ModifierUtil和ReflectUtil增加removeFinalModify
This commit is contained in:
parent
0941210553
commit
eef7943d8a
@ -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 】 StreamUtil.of方法新增对 Iterator 支持;StreamUtil.of(Iterable) 方法优化(pr#807@Gitee)
|
||||||
* 【core 】 增加.wgt格式的MimeType(pr#2617@Github)
|
* 【core 】 增加.wgt格式的MimeType(pr#2617@Github)
|
||||||
* 【core 】 EnumUtil.getBy增加带默认值重载(issue#I5RZU6@Gitee)
|
* 【core 】 EnumUtil.getBy增加带默认值重载(issue#I5RZU6@Gitee)
|
||||||
|
* 【core 】 ModifierUtil和ReflectUtil增加removeFinalModify(pr#810@Gitee)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【core 】 修复FileNameUtil.cleanInvalid无法去除换行符问题(issue#I5RMZV@Gitee)
|
* 【core 】 修复FileNameUtil.cleanInvalid无法去除换行符问题(issue#I5RMZV@Gitee)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.hutool.core.util;
|
package cn.hutool.core.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -262,6 +264,58 @@ public class ModifierUtil {
|
|||||||
public static boolean isAbstract(Method method) {
|
public static boolean isAbstract(Method method) {
|
||||||
return hasModifier(method, ModifierType.ABSTRACT);
|
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>基本类型的包装类 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 (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
|
//-------------------------------------------------------------------------------------------------------- Private method start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +9,6 @@ import cn.hutool.core.exceptions.InvocationTargetRuntimeException;
|
|||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.Filter;
|
import cn.hutool.core.lang.Filter;
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import cn.hutool.core.lang.reflect.MethodHandleUtil;
|
import cn.hutool.core.lang.reflect.MethodHandleUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.map.WeakConcurrentMap;
|
import cn.hutool.core.map.WeakConcurrentMap;
|
||||||
@ -1141,26 +1140,7 @@ public class ReflectUtil {
|
|||||||
* @author dazer
|
* @author dazer
|
||||||
*/
|
*/
|
||||||
public static void removeFinalModify(Field field) {
|
public static void removeFinalModify(Field field) {
|
||||||
if (field != null) {
|
ModifierUtil.removeFinalModify(field);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +74,7 @@ public class ReflectUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getFieldTest() {
|
public void getFieldTest() {
|
||||||
// 能够获取到父类字段
|
// 能够获取到父类字段
|
||||||
Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
|
final Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
|
||||||
Assert.assertNotNull(privateField);
|
Assert.assertNotNull(privateField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,14 +87,14 @@ public class ReflectUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setFieldTest() {
|
public void setFieldTest() {
|
||||||
TestClass testClass = new TestClass();
|
final TestClass testClass = new TestClass();
|
||||||
ReflectUtil.setFieldValue(testClass, "a", "111");
|
ReflectUtil.setFieldValue(testClass, "a", "111");
|
||||||
Assert.assertEquals(111, testClass.getA());
|
Assert.assertEquals(111, testClass.getA());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invokeTest() {
|
public void invokeTest() {
|
||||||
TestClass testClass = new TestClass();
|
final TestClass testClass = new TestClass();
|
||||||
ReflectUtil.invoke(testClass, "setA", 10);
|
ReflectUtil.invoke(testClass, "setA", 10);
|
||||||
Assert.assertEquals(10, testClass.getA());
|
Assert.assertEquals(10, testClass.getA());
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ public class ReflectUtilTest {
|
|||||||
private String n;
|
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)) {
|
if (null == clazz || StrUtil.isBlank(methodName)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ public class ReflectUtilTest {
|
|||||||
Method res = null;
|
Method res = null;
|
||||||
final Method[] methods = ReflectUtil.getMethods(clazz);
|
final Method[] methods = ReflectUtil.getMethods(clazz);
|
||||||
if (ArrayUtil.isNotEmpty(methods)) {
|
if (ArrayUtil.isNotEmpty(methods)) {
|
||||||
for (Method method : methods) {
|
for (final Method method : methods) {
|
||||||
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
|
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||||
&& (res == null
|
&& (res == null
|
||||||
@ -252,22 +252,22 @@ public class ReflectUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void newInstanceIfPossibleTest(){
|
public void newInstanceIfPossibleTest(){
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
int intValue = ReflectUtil.newInstanceIfPossible(int.class);
|
final int intValue = ReflectUtil.newInstanceIfPossible(int.class);
|
||||||
Assert.assertEquals(0, intValue);
|
Assert.assertEquals(0, intValue);
|
||||||
|
|
||||||
Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
|
final Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
|
||||||
Assert.assertEquals(new Integer(0), integer);
|
Assert.assertEquals(new Integer(0), integer);
|
||||||
|
|
||||||
Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
|
final Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
|
||||||
Assert.assertNotNull(map);
|
Assert.assertNotNull(map);
|
||||||
|
|
||||||
Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
|
final Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
|
||||||
Assert.assertNotNull(collection);
|
Assert.assertNotNull(collection);
|
||||||
|
|
||||||
Week week = ReflectUtil.newInstanceIfPossible(Week.class);
|
final Week week = ReflectUtil.newInstanceIfPossible(Week.class);
|
||||||
Assert.assertEquals(Week.SUNDAY, week);
|
Assert.assertEquals(Week.SUNDAY, week);
|
||||||
|
|
||||||
int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
|
final int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
|
||||||
Assert.assertArrayEquals(new int[0], intArray);
|
Assert.assertArrayEquals(new int[0], intArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,8 +277,8 @@ public class ReflectUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setFieldValueTest() {
|
public void setFieldValueWithFinalTest() {
|
||||||
String fieldName = "DIALECTS";
|
final String fieldName = "DIALECTS";
|
||||||
final List<Number> dialects =
|
final List<Number> dialects =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
1,
|
1,
|
||||||
@ -286,7 +286,7 @@ public class ReflectUtilTest {
|
|||||||
3,
|
3,
|
||||||
99
|
99
|
||||||
);
|
);
|
||||||
Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
|
final Field field = ReflectUtil.getField(JdbcDialects.class, fieldName);
|
||||||
ReflectUtil.removeFinalModify(field);
|
ReflectUtil.removeFinalModify(field);
|
||||||
ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);
|
ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user