From 449df10509f0723e62871e42fde43e925855249c Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 26 Nov 2025 16:30:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`ReflectUtil.newInstanceIfPos?= =?UTF-8?q?sible`=E4=BC=A0=E5=85=A5Object=E9=80=BB=E8=BE=91=E9=94=99?= =?UTF-8?q?=E8=AF=AF=EF=BC=88pr#4160@Github=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../java/cn/hutool/core/util/ReflectUtil.java | 20 +++-- .../cn/hutool/core/util/ReflectUtilTest.java | 75 ++++++++++++++----- 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a4647373..a43546d7e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ * 【core 】 修复`URLUtil.url`未断开连接问题(pr#4149@Github) * 【core 】 修复`Bimap.put`重复put问题(pr#4150@Github) * 【core 】 修复`StrUtil.str(ByteBuffer, Charset)` 方法修改入参 `ByteBuffer` 的 `position`,导致入参变化 (pr#4153@Github) +* 【core 】 修复`ReflectUtil.newInstanceIfPossible`传入Object逻辑错误(pr#4160@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.41(2025-10-12) 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 3df08e42f..1470b7437 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 @@ -888,13 +888,19 @@ public class ReflectUtil { return (T) ClassUtil.getPrimitiveDefaultValue(type); } - // 某些特殊接口的实例化按照默认实现进行 - if (type.isAssignableFrom(AbstractMap.class)) { - type = (Class) HashMap.class; - } else if (type.isAssignableFrom(List.class)) { - type = (Class) ArrayList.class; - } else if (type.isAssignableFrom(Set.class)) { - type = (Class) HashSet.class; + if (Object.class != type) { + // 某些特殊接口的实例化按照默认实现进行 + if (type.isAssignableFrom(AbstractMap.class)) { + type = (Class) HashMap.class; + } else if (type.isAssignableFrom(List.class)) { + type = (Class) ArrayList.class; + } else if (type.isAssignableFrom(Set.class)) { + type = (Class) HashSet.class; + } else if (type.isAssignableFrom(Queue.class)) { + type = (Class) LinkedList.class; + } else if (type.isAssignableFrom(Deque.class)) { + type = (Class) LinkedList.class; + } } try { 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 11529a9d3..48e2046e2 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 @@ -151,7 +151,7 @@ public class ReflectUtilTest { final TestClass testClass = new TestClass(); final Method method = ReflectUtil.getMethod(TestClass.class, "setA", int.class); assertThrows(IllegalArgumentException.class, - () -> ReflectUtil.invoke(testClass, method, "NaN")); + () -> ReflectUtil.invoke(testClass, method, "NaN")); } @Test @@ -210,6 +210,7 @@ public class ReflectUtilTest { private String n; } + @SuppressWarnings("UnusedReturnValue") 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; @@ -220,9 +221,9 @@ public class ReflectUtilTest { if (ArrayUtil.isNotEmpty(methods)) { for (final Method method : methods) { if (StrUtil.equals(methodName, method.getName(), ignoreCase) - && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) - && (res == null - || res.getReturnType().isAssignableFrom(method.getReturnType()))) { + && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) + && (res == null + || res.getReturnType().isAssignableFrom(method.getReturnType()))) { res = method; } } @@ -300,6 +301,7 @@ public class ReflectUtilTest { } class C2 extends C1 { + @SuppressWarnings("RedundantMethodOverride") @Override public void getA() { @@ -307,7 +309,7 @@ public class ReflectUtilTest { } @Test - public void newInstanceIfPossibleTest(){ + public void newInstanceIfPossibleTest() { //noinspection ConstantConditions final int intValue = ReflectUtil.newInstanceIfPossible(int.class); assertEquals(0, intValue); @@ -330,19 +332,19 @@ public class ReflectUtilTest { public static class JdbcDialects { private static final List DIALECTS = - Arrays.asList(1L, 2L, 3L); + Arrays.asList(1L, 2L, 3L); } @Test public void setFieldValueWithFinalTest() { final String fieldName = "DIALECTS"; final List dialects = - Arrays.asList( - 1, - 2, - 3, - 99 - ); + Arrays.asList( + 1, + 2, + 3, + 99 + ); final Field field = ReflectUtil.getField(JdbcDialects.class, fieldName); ReflectUtil.removeFinalModify(field); ReflectUtil.setFieldValue(JdbcDialects.class, fieldName, dialects); @@ -351,24 +353,63 @@ public class ReflectUtilTest { } @Test - public void issue2625Test(){ + public void issue2625Test() { // 内部类继承的情况下父类方法会被定义为桥接方法,因此按照pr#1965@Github判断返回值的继承关系来代替判断桥接。 final Method getThis = ReflectUtil.getMethod(A.C.class, "getThis"); assertTrue(getThis.isBridge()); } @SuppressWarnings("InnerClassMayBeStatic") - public class A{ + public class A { - public class C extends B{ + public class C extends B { } - protected class B{ - public B getThis(){ + protected class B { + public B getThis() { return this; } } } + @Test + public void newInstanceIfPossibleTest2() { + // 测试Object.class不应该被错误地实例化为HashMap,应该返回Object实例 + Object objectInstance = ReflectUtil.newInstanceIfPossible(Object.class); + assertNotNull(objectInstance); + assertEquals(Object.class, objectInstance.getClass()); + + // 测试Map.class能够正确实例化为HashMap + Map mapInstance = ReflectUtil.newInstanceIfPossible(Map.class); + assertNotNull(mapInstance); + assertInstanceOf(HashMap.class, mapInstance); + + // 测试Collection.class能够正确实例化为ArrayList + Collection collectionInstance = ReflectUtil.newInstanceIfPossible(Collection.class); + assertNotNull(collectionInstance); + assertInstanceOf(ArrayList.class, collectionInstance); + + + // 测试List.class能够正确实例化为ArrayList + List listInstance = ReflectUtil.newInstanceIfPossible(List.class); + assertNotNull(listInstance); + assertInstanceOf(ArrayList.class, listInstance); + + // 测试Set.class能够正确实例化为HashSet + Set setInstance = ReflectUtil.newInstanceIfPossible(Set.class); + assertNotNull(setInstance); + assertInstanceOf(HashSet.class, setInstance); + + // 测试Queue接口能够正确实例化为LinkedList + Queue queueInstance = ReflectUtil.newInstanceIfPossible(Queue.class); + assertNotNull(queueInstance); + assertInstanceOf(LinkedList.class, queueInstance); + + // 测试Deque接口能够正确实例化为LinkedList + Deque dequeInstance = ReflectUtil.newInstanceIfPossible(Deque.class); + assertNotNull(dequeInstance); + assertInstanceOf(LinkedList.class, dequeInstance); + } + }