From c7c64e167e15e1f8d81c89ee48fd381ce24ad2bb Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 30 Jun 2023 18:17:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DTypeUtil.getTypeArgument?= =?UTF-8?q?=E5=AF=B9=E5=AE=9E=E7=8E=B0=E6=8E=A5=E5=8F=A3=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8D=E5=85=A8=E9=9D=A2=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../java/cn/hutool/core/util/TypeUtil.java | 77 +++++++++++++++---- .../cn/hutool/core/date/DateUtilTest.java | 12 --- .../cn/hutool/core/util/IssueI7CRIWTest.java | 59 ++++++++++++++ 4 files changed, 123 insertions(+), 26 deletions(-) create mode 100755 hutool-core/src/test/java/cn/hutool/core/util/IssueI7CRIWTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d0169589..5bdcd9eaf 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * 【setting】 修复utf8-bom的setting文件读取问题(issue#I7G34E@Gitee) * 【core 】 修复PathUtil.getMimeType可能造成的异常(issue#3179@Github) * 【core 】 修复Pair序列化转换无效问题(issue#I7GPGX@Github) +* 【core 】 修复TypeUtil.getTypeArgument对实现接口获取不全面问题(issue#I7CRIW@Gitee) ------------------------------------------------------------------------------------------------------------- # 5.8.20(2023-06-16) diff --git a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java index f962b5174..8188694e4 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java @@ -1,5 +1,6 @@ package cn.hutool.core.util; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.ParameterizedTypeImpl; import cn.hutool.core.lang.reflect.ActualTypeMapperPool; @@ -9,6 +10,8 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -263,24 +266,70 @@ public class TypeUtil { * @return {@link ParameterizedType} * @since 4.5.2 */ - public static ParameterizedType toParameterizedType(Type type) { - ParameterizedType result = null; + public static ParameterizedType toParameterizedType(final Type type) { + return toParameterizedType(type, 0); + } + + /** + * 将{@link Type} 转换为{@link ParameterizedType}
+ * {@link ParameterizedType}用于获取当前类或父类中泛型参数化后的类型
+ * 一般用于获取泛型参数具体的参数类型,例如: + * + *
{@code
+	 *   class A
+	 *   class B extends A;
+	 * }
+ *

+ * 通过此方法,传入B.class即可得到B对应的{@link ParameterizedType},从而获取到String + * + * @param type {@link Type} + * @param interfaceIndex 实现的第几个接口 + * @return {@link ParameterizedType} + * @since 4.5.2 + */ + public static ParameterizedType toParameterizedType(final Type type, final int interfaceIndex) { if (type instanceof ParameterizedType) { - result = (ParameterizedType) type; - } else if (type instanceof Class) { - final Class clazz = (Class) type; - Type genericSuper = clazz.getGenericSuperclass(); - if (null == genericSuper || Object.class.equals(genericSuper)) { - // 如果类没有父类,而是实现一些定义好的泛型接口,则取接口的Type - final Type[] genericInterfaces = clazz.getGenericInterfaces(); - if (ArrayUtil.isNotEmpty(genericInterfaces)) { - // 默认取第一个实现接口的泛型Type - genericSuper = genericInterfaces[0]; + return (ParameterizedType) type; + } + + if (type instanceof Class) { + final ParameterizedType[] generics = getGenerics((Class) type); + if(generics.length > interfaceIndex){ + return generics[interfaceIndex]; + } + } + + return null; + } + + /** + * 获取指定类所有泛型父类和泛型接口 + * + * @param clazz 类 + * @return 泛型父类或接口数组 + * @since 6.0.0 + */ + public static ParameterizedType[] getGenerics(final Class clazz) { + final List result = new ArrayList<>(); + // 泛型父类(父类及祖类优先级高) + final Type genericSuper = clazz.getGenericSuperclass(); + if(null != genericSuper && !Object.class.equals(genericSuper)){ + final ParameterizedType parameterizedType = toParameterizedType(genericSuper); + if(null != parameterizedType){ + result.add(parameterizedType); + } + } + + // 泛型接口 + final Type[] genericInterfaces = clazz.getGenericInterfaces(); + if (ArrayUtil.isNotEmpty(genericInterfaces)) { + for (final Type genericInterface : genericInterfaces) { + if (genericInterface instanceof ParameterizedType) { + result.add((ParameterizedType) genericInterface); } } - result = toParameterizedType(genericSuper); } - return result; + return result.toArray(new ParameterizedType[0]); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 271590442..9a9ed5a13 100755 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -1130,18 +1130,6 @@ public class DateUtilTest { Assert.assertEquals("2021-03-17 06:31:33", dateTime3.toString()); } - /** - * issue#I6E6ZG 法定年龄/周岁/实岁计算 - */ - @Test - public void ageOfNowTest() { - final DateTime concurrentDate = DateUtil.date(); - final DateTime birthDay = DateUtil.offset(concurrentDate, DateField.YEAR, -71); - Assert.assertEquals(70, DateUtil.ageOfNow(birthDay)); - Assert.assertEquals(71, DateUtil.ageOfNow(DateUtil.offsetDay(birthDay, -1))); - Assert.assertEquals(0, DateUtil.ageOfNow(concurrentDate)); - } - @Test public void calendarTest() { final Date date = DateUtil.date(); diff --git a/hutool-core/src/test/java/cn/hutool/core/util/IssueI7CRIWTest.java b/hutool-core/src/test/java/cn/hutool/core/util/IssueI7CRIWTest.java new file mode 100755 index 000000000..c94e943c8 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/util/IssueI7CRIWTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.core.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Type; + +public class IssueI7CRIWTest { + @Test + public void getTypeArgumentsTest() { + // 无法从继承获取泛型,则从接口获取 + Type type = TypeUtil.getTypeArgument(C.class); + Assert.assertEquals(type, String.class); + + // 继承和第一个接口都非泛型接口,则从找到的第一个泛型接口获取 + type = TypeUtil.getTypeArgument(D.class); + Assert.assertEquals(type, String.class); + } + + static class A{ + + } + + static class AT{ + + } + + interface Face1{ + + } + + interface Face2{ + + } + + static class B extends A{ + + } + + static class C extends A implements Face1{ + + } + + static class D extends A implements Face2, Face1{ + + } +}