diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c0aead78..61b139015 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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格式的MimeType(pr#2617@Github) * 【core 】 EnumUtil.getBy增加带默认值重载(issue#I5RZU6@Gitee) +* 【core 】 ModifierUtil和ReflectUtil增加removeFinalModify(pr#810@Gitee) ### 🐞Bug修复 * 【core 】 修复FileNameUtil.cleanInvalid无法去除换行符问题(issue#I5RMZV@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ModifierUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ModifierUtil.java index dec42bed0..224950a94 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ModifierUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ModifierUtil.java @@ -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字段可以被修改 + *

+ * 只要不会被编译器内联优化的 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 (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 /** 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 d56e01966..f61027b0a 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,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); } /** 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 6170ec61b..3b82a70a6 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 @@ -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 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);