From 1f78ab8aa088b8647544fbe3e10c747e775ea291 Mon Sep 17 00:00:00 2001 From: guanchengang <1620522809@qq.com> Date: Sat, 9 Aug 2025 14:57:46 +0800 Subject: [PATCH 01/11] optimize TypeParameterResolver --- .../reflection/TypeParameterResolver.java | 74 +++++++++++++++---- .../reflection/TypeParameterResolverTest.java | 37 +++++++++- 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index aba6a7f3e4d..f9d56b60136 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -129,9 +129,10 @@ private static Type resolveGenericArrayType(GenericArrayType genericArrayType, T private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class declaringClass) { Class rawType = (Class) parameterizedType.getRawType(); + Type ownerType = parameterizedType.getOwnerType(); Type[] typeArgs = parameterizedType.getActualTypeArguments(); Type[] args = resolveTypes(typeArgs, srcType, declaringClass); - return new ParameterizedTypeImpl(rawType, null, args); + return new ParameterizedTypeImpl(rawType, ownerType, args); } private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class declaringClass) { @@ -158,7 +159,7 @@ private static Type resolveTypeVar(TypeVariable typeVar, Type srcType, Class< } } else { throw new IllegalArgumentException( - "The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass()); + "The srcType(2nd arg) must be Class or ParameterizedType, but was: " + srcType.getClass()); } if (clazz == declaringClass) { @@ -198,7 +199,7 @@ private static Type scanSuperTypes(TypeVariable typeVar, Type srcType, Class< for (int i = 0; i < parentTypeVars.length; i++) { if (typeVar.equals(parentTypeVars[i])) { Type actualType = parentAsType.getActualTypeArguments()[i]; - return actualType instanceof TypeVariable ? Object.class : actualType; + return actualType instanceof TypeVariable ? ((TypeVariable) actualType).getBounds()[0] : actualType; } } } @@ -230,7 +231,40 @@ private static ParameterizedType translateParentTypeVars(ParameterizedType srcTy newParentArgs[i] = parentTypeArgs[i]; } } - return noChange ? parentType : new ParameterizedTypeImpl((Class) parentType.getRawType(), null, newParentArgs); + if (noChange && !(parentType instanceof ParameterizedTypeImpl)) noChange = false; + return noChange + ? parentType + : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); + } + + private static Type canonicalize(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) type; + return new ParameterizedTypeImpl((Class) p.getRawType(), p.getOwnerType(), p.getActualTypeArguments()); + } + else if (type instanceof GenericArrayType) { + GenericArrayType g = (GenericArrayType) type; + return new GenericArrayTypeImpl(g.getGenericComponentType()); + } + else if (type instanceof WildcardType) { + WildcardType w = (WildcardType) type; + return new WildcardTypeImpl(w.getLowerBounds(), w.getUpperBounds()); + } + else { + return type; + } + } + + private static Type[] canonicalizeTypes(Type[] types) { + if (types == null || types.length == 0) { + return new Type[0]; + } + int length = types.length; + Type[] canonicalizedTypes = new Type[length]; + for (int i = 0; i < length; i++) { + canonicalizedTypes[i] = canonicalize(types[i]); + } + return canonicalizedTypes; } private TypeParameterResolver() { @@ -244,11 +278,11 @@ static class ParameterizedTypeImpl implements ParameterizedType { private final Type[] actualTypeArguments; - public ParameterizedTypeImpl(Class rawType, Type ownerType, Type[] actualTypeArguments) { + ParameterizedTypeImpl(Class rawType, Type ownerType, Type[] actualTypeArguments) { super(); - this.rawType = rawType; - this.ownerType = ownerType; - this.actualTypeArguments = actualTypeArguments; + this.rawType = (Class) canonicalize(rawType); + this.ownerType = canonicalize(ownerType); + this.actualTypeArguments = canonicalizeTypes(actualTypeArguments); } @Override @@ -283,7 +317,21 @@ public boolean equals(Object obj) { @Override public String toString() { - StringBuilder s = new StringBuilder().append(rawType.getName()).append("<"); + StringBuilder s = new StringBuilder(); + if (ownerType != null) { + s.append(ownerType.getTypeName()).append("$"); + if (ownerType instanceof ParameterizedTypeImpl) { + // remove prefixes that do not contain generic information + s.append( + rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); + } + else { + s.append(rawType.getSimpleName()); + } + } else { + s.append(rawType.getName()); + } + s.append("<"); for (int i = 0; i < actualTypeArguments.length; i++) { if (i > 0) { s.append(", "); @@ -301,8 +349,8 @@ static class WildcardTypeImpl implements WildcardType { WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) { super(); - this.lowerBounds = lowerBounds; - this.upperBounds = upperBounds; + this.lowerBounds = canonicalizeTypes(lowerBounds); + this.upperBounds = canonicalizeTypes(upperBounds); } @Override @@ -353,7 +401,7 @@ static class GenericArrayTypeImpl implements GenericArrayType { GenericArrayTypeImpl(Type genericComponentType) { super(); - this.genericComponentType = genericComponentType; + this.genericComponentType = canonicalize(genericComponentType); } @Override @@ -380,7 +428,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return new StringBuilder().append(genericComponentType.toString()).append("[]").toString(); + return new StringBuilder().append(genericComponentType.getTypeName()).append("[]").toString(); } } } diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index ca4bb535570..d0599aa335b 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; @@ -230,7 +231,6 @@ void returnLv2ArrayOfArray() throws Exception { Type result = TypeParameterResolver.resolveReturnType(method, clazz); assertTrue(result instanceof Class); Class resultClass = (Class) result; - assertTrue(result instanceof Class); assertTrue(resultClass.isArray()); assertTrue(resultClass.getComponentType().isArray()); assertEquals(String.class, resultClass.getComponentType().getComponentType()); @@ -513,6 +513,41 @@ void shouldResolveInterfaceTypeParamsDeeper() { assertEquals(String.class, types[0]); } + @Test + void shouldResolveWildcardTypeInClassDefinition() throws Exception { + class A { + public T foo(T t) { + return t; + } + } + + class B extends A { + + } + + class C1 extends B { + + } + + class C2 extends B { + + } + + class C3 extends B { + + } + + Method m = A.class.getMethod("foo", Serializable.class); + + assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C1.class)); + assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C2.class)); + assertEquals(Number.class, TypeParameterResolver.resolveReturnType(m, C3.class)); + + assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C1.class)[0]); + assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C2.class)[0]); + assertEquals(Number.class, TypeParameterResolver.resolveParamTypes(m, C3.class)[0]); + } + class AA { } From 9777d90aa3d8b637365721c9f355337b721f53d1 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sat, 16 Aug 2025 05:40:02 +0900 Subject: [PATCH 02/11] Formatted by maven plugin --- .../reflection/TypeParameterResolver.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index f9d56b60136..b358b0fdfa1 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -231,26 +231,23 @@ private static ParameterizedType translateParentTypeVars(ParameterizedType srcTy newParentArgs[i] = parentTypeArgs[i]; } } - if (noChange && !(parentType instanceof ParameterizedTypeImpl)) noChange = false; - return noChange - ? parentType - : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); + if (noChange && !(parentType instanceof ParameterizedTypeImpl)) + noChange = false; + return noChange ? parentType + : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); } private static Type canonicalize(Type type) { if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; return new ParameterizedTypeImpl((Class) p.getRawType(), p.getOwnerType(), p.getActualTypeArguments()); - } - else if (type instanceof GenericArrayType) { + } else if (type instanceof GenericArrayType) { GenericArrayType g = (GenericArrayType) type; return new GenericArrayTypeImpl(g.getGenericComponentType()); - } - else if (type instanceof WildcardType) { + } else if (type instanceof WildcardType) { WildcardType w = (WildcardType) type; return new WildcardTypeImpl(w.getLowerBounds(), w.getUpperBounds()); - } - else { + } else { return type; } } @@ -322,10 +319,8 @@ public String toString() { s.append(ownerType.getTypeName()).append("$"); if (ownerType instanceof ParameterizedTypeImpl) { // remove prefixes that do not contain generic information - s.append( - rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); - } - else { + s.append(rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); + } else { s.append(rawType.getSimpleName()); } } else { From 287764e60056600ec7cdf97773e80178aa8dbae9 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sat, 16 Aug 2025 05:39:28 +0900 Subject: [PATCH 03/11] Added a test case ensures nested ParameterizedType equality --- .../reflection/TypeParameterResolverTest.java | 18 ++++++++++++++++++ .../reflection/typeparam/Level0Mapper.java | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index d0599aa335b..0d3e4f9982f 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -588,4 +589,21 @@ public List m() { } } + @Test + void shouldParameterizedTypesWithOwnerTypeBeEqual() throws Exception { + class Clazz { + @SuppressWarnings("unused") + public Entry entry() { + return null; + } + } + + Type typeJdk = Clazz.class.getMethod("entry").getGenericReturnType(); + + Class clazz = Level2Mapper.class; + Method method = clazz.getMethod("selectEntry"); + Type typeMybatis = TypeParameterResolver.resolveReturnType(method, clazz); + + assertEquals(typeMybatis, typeJdk); + } } diff --git a/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java b/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java index 7f108541f6e..b6de2eb0fec 100644 --- a/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java +++ b/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2022 the original author or authors. + * Copyright 2009-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; +import java.util.Map.Entry; public interface Level0Mapper { @@ -46,6 +47,8 @@ public interface Level0Mapper { Map selectMap(); + Entry selectEntry(); + N[] selectArray(List[] param); N[][] selectArrayOfArray(); From c2b57a4ac67018a42f4c0839c048ae1bfb5c4681 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Mon, 8 Sep 2025 05:50:34 +0900 Subject: [PATCH 04/11] A test for new `toString()` logic Not fully covered yet --- .../ibatis/reflection/TypeParameterResolverTest.java | 9 +++++++++ .../apache/ibatis/reflection/typeparam/Level0Mapper.java | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index 0d3e4f9982f..2d97fca182d 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -606,4 +606,13 @@ public Entry entry() { assertEquals(typeMybatis, typeJdk); } + + @Test + void shouldNestedParamTypeToStringOmitCommonFqn() throws Exception { + Class clazz = Level2Mapper.class; + Method method = clazz.getMethod("selectMapEntry"); + Type type = TypeParameterResolver.resolveReturnType(method, clazz); + assertEquals("java.util.Map, java.util.Date>", + type.toString()); + } } diff --git a/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java b/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java index b6de2eb0fec..d44e50fe62d 100644 --- a/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java +++ b/src/test/java/org/apache/ibatis/reflection/typeparam/Level0Mapper.java @@ -49,6 +49,8 @@ public interface Level0Mapper { Entry selectEntry(); + Map, L> selectMapEntry(); + N[] selectArray(List[] param); N[][] selectArrayOfArray(); From a863e58e381d63d1d8027804788d494a30f272b1 Mon Sep 17 00:00:00 2001 From: guanchengang <1620522809@qq.com> Date: Mon, 8 Sep 2025 15:50:34 +0800 Subject: [PATCH 05/11] remove unnecessary part and add a test for inner class --- .../reflection/TypeParameterResolver.java | 71 +++++----------- .../reflection/TypeParameterResolverTest.java | 80 ++++++++++--------- 2 files changed, 65 insertions(+), 86 deletions(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index b358b0fdfa1..c9a3f74d2de 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -199,7 +199,7 @@ private static Type scanSuperTypes(TypeVariable typeVar, Type srcType, Class< for (int i = 0; i < parentTypeVars.length; i++) { if (typeVar.equals(parentTypeVars[i])) { Type actualType = parentAsType.getActualTypeArguments()[i]; - return actualType instanceof TypeVariable ? ((TypeVariable) actualType).getBounds()[0] : actualType; + return actualType instanceof TypeVariable ? Object.class : actualType; } } } @@ -231,37 +231,9 @@ private static ParameterizedType translateParentTypeVars(ParameterizedType srcTy newParentArgs[i] = parentTypeArgs[i]; } } - if (noChange && !(parentType instanceof ParameterizedTypeImpl)) - noChange = false; - return noChange ? parentType - : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); - } - - private static Type canonicalize(Type type) { - if (type instanceof ParameterizedType) { - ParameterizedType p = (ParameterizedType) type; - return new ParameterizedTypeImpl((Class) p.getRawType(), p.getOwnerType(), p.getActualTypeArguments()); - } else if (type instanceof GenericArrayType) { - GenericArrayType g = (GenericArrayType) type; - return new GenericArrayTypeImpl(g.getGenericComponentType()); - } else if (type instanceof WildcardType) { - WildcardType w = (WildcardType) type; - return new WildcardTypeImpl(w.getLowerBounds(), w.getUpperBounds()); - } else { - return type; - } - } - - private static Type[] canonicalizeTypes(Type[] types) { - if (types == null || types.length == 0) { - return new Type[0]; - } - int length = types.length; - Type[] canonicalizedTypes = new Type[length]; - for (int i = 0; i < length; i++) { - canonicalizedTypes[i] = canonicalize(types[i]); - } - return canonicalizedTypes; + return noChange + ? parentType + : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); } private TypeParameterResolver() { @@ -277,9 +249,9 @@ static class ParameterizedTypeImpl implements ParameterizedType { ParameterizedTypeImpl(Class rawType, Type ownerType, Type[] actualTypeArguments) { super(); - this.rawType = (Class) canonicalize(rawType); - this.ownerType = canonicalize(ownerType); - this.actualTypeArguments = canonicalizeTypes(actualTypeArguments); + this.rawType = rawType; + this.ownerType = ownerType; + this.actualTypeArguments = actualTypeArguments; } @Override @@ -317,23 +289,22 @@ public String toString() { StringBuilder s = new StringBuilder(); if (ownerType != null) { s.append(ownerType.getTypeName()).append("$"); - if (ownerType instanceof ParameterizedTypeImpl) { - // remove prefixes that do not contain generic information - s.append(rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); - } else { - s.append(rawType.getSimpleName()); - } + s.append(rawType.getSimpleName()); } else { s.append(rawType.getName()); } - s.append("<"); - for (int i = 0; i < actualTypeArguments.length; i++) { - if (i > 0) { - s.append(", "); + int argLength = actualTypeArguments.length; + if (argLength > 0) { + s.append("<"); + for (int i = 0; i < argLength; i++) { + if (i > 0) { + s.append(", "); + } + s.append(actualTypeArguments[i].getTypeName()); } - s.append(actualTypeArguments[i].getTypeName()); + s.append(">"); } - return s.append(">").toString(); + return s.toString(); } } @@ -344,8 +315,8 @@ static class WildcardTypeImpl implements WildcardType { WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) { super(); - this.lowerBounds = canonicalizeTypes(lowerBounds); - this.upperBounds = canonicalizeTypes(upperBounds); + this.lowerBounds = lowerBounds; + this.upperBounds = upperBounds; } @Override @@ -396,7 +367,7 @@ static class GenericArrayTypeImpl implements GenericArrayType { GenericArrayTypeImpl(Type genericComponentType) { super(); - this.genericComponentType = canonicalize(genericComponentType); + this.genericComponentType = genericComponentType; } @Override diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index 2d97fca182d..18c182af741 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; @@ -514,41 +513,6 @@ void shouldResolveInterfaceTypeParamsDeeper() { assertEquals(String.class, types[0]); } - @Test - void shouldResolveWildcardTypeInClassDefinition() throws Exception { - class A { - public T foo(T t) { - return t; - } - } - - class B extends A { - - } - - class C1 extends B { - - } - - class C2 extends B { - - } - - class C3 extends B { - - } - - Method m = A.class.getMethod("foo", Serializable.class); - - assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C1.class)); - assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C2.class)); - assertEquals(Number.class, TypeParameterResolver.resolveReturnType(m, C3.class)); - - assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C1.class)[0]); - assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C2.class)[0]); - assertEquals(Number.class, TypeParameterResolver.resolveParamTypes(m, C3.class)[0]); - } - class AA { } @@ -615,4 +579,48 @@ void shouldNestedParamTypeToStringOmitCommonFqn() throws Exception { assertEquals("java.util.Map, java.util.Date>", type.toString()); } + + static class Outer { + + class Inner { + } + + public Inner foo() { + return null; + } + + } + + static class InnerTester { + + public Outer.Inner noTypeOuter() { + return null; + } + + public Outer.Inner stringTypeOuter() { + return null; + } + + } + + @Test + void shouldToStringHandleInnerClass() throws Exception { + Class outerClass = Outer.class; + Class innerTesterClass = InnerTester.class; + Method foo = outerClass.getMethod("foo"); + Method noTypeOuter = innerTesterClass.getMethod("noTypeOuter"); + Method stringTypeOuter = innerTesterClass.getMethod("stringTypeOuter"); + + Type fooReturnType = TypeParameterResolver.resolveReturnType(foo, outerClass); + Type noTypeOuterReturnType = TypeParameterResolver.resolveReturnType(noTypeOuter, innerTesterClass); + Type stringTypeOuterReturnType = TypeParameterResolver.resolveReturnType(stringTypeOuter, innerTesterClass); + + assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", + fooReturnType.toString()); + assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", + noTypeOuterReturnType.toString()); + assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", + stringTypeOuterReturnType.toString()); + } + } From 39ccc50c93dff00ef43cee6051a5a461fadee42a Mon Sep 17 00:00:00 2001 From: guanchengang <1620522809@qq.com> Date: Mon, 8 Sep 2025 16:55:47 +0800 Subject: [PATCH 06/11] Modify equals() in WildcardTypeImpl and GenericArrayTypeImpl --- .../ibatis/reflection/TypeParameterResolver.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index c9a3f74d2de..d6472022d9f 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -343,11 +343,11 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (!(obj instanceof WildcardTypeImpl)) { + if (!(obj instanceof WildcardType)) { return false; } - WildcardTypeImpl other = (WildcardTypeImpl) obj; - return Arrays.equals(lowerBounds, other.lowerBounds) && Arrays.equals(upperBounds, other.upperBounds); + WildcardType other = (WildcardType) obj; + return Arrays.equals(lowerBounds, other.getLowerBounds()) && Arrays.equals(upperBounds, other.getUpperBounds()); } @Override @@ -385,11 +385,11 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (!(obj instanceof GenericArrayTypeImpl)) { + if (!(obj instanceof GenericArrayType)) { return false; } - GenericArrayTypeImpl other = (GenericArrayTypeImpl) obj; - return Objects.equals(genericComponentType, other.genericComponentType); + GenericArrayType other = (GenericArrayType) obj; + return Objects.equals(genericComponentType, other.getGenericComponentType()); } @Override From d88812c70874b5421b7ecd176fc6e6e6cf14f48d Mon Sep 17 00:00:00 2001 From: guanchengang <1620522809@qq.com> Date: Tue, 9 Sep 2025 10:12:06 +0800 Subject: [PATCH 07/11] added tests for `equals()` --- .../reflection/TypeParameterResolverTest.java | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index 18c182af741..da151b7b8b0 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; @@ -568,7 +569,48 @@ public Entry entry() { Method method = clazz.getMethod("selectEntry"); Type typeMybatis = TypeParameterResolver.resolveReturnType(method, clazz); - assertEquals(typeMybatis, typeJdk); + assertTrue(typeJdk instanceof ParameterizedType && !(typeJdk instanceof TypeParameterResolver.ParameterizedTypeImpl)); + assertTrue(typeMybatis instanceof TypeParameterResolver.ParameterizedTypeImpl); + assertEquals(typeMybatis.equals(typeJdk), typeJdk.equals(typeMybatis)); + } + + @Test + void shouldWildcardTypeBeEqual() throws Exception { + class WildcardTypeTester { + public List foo() { + return null; + } + } + + Class clazz = WildcardTypeTester.class; + Method foo = clazz.getMethod("foo"); + Type typeMybatis = TypeParameterResolver.resolveReturnType(foo, clazz); + Type typeJdk = foo.getGenericReturnType(); + + Type wildcardMybatis = ((ParameterizedType) typeMybatis).getActualTypeArguments()[0]; + Type wildcardJdk = ((ParameterizedType) typeJdk).getActualTypeArguments()[0]; + + assertTrue(wildcardJdk instanceof WildcardType && !(wildcardJdk instanceof TypeParameterResolver.WildcardTypeImpl)); + assertTrue(wildcardMybatis instanceof TypeParameterResolver.WildcardTypeImpl); + assertEquals(wildcardMybatis.equals(wildcardJdk), wildcardJdk.equals(wildcardMybatis)); + } + + @Test + void shouldGenericArrayTypeBeEqual() throws Exception { + class GenericArrayTypeTester { + public List[] foo() { + return null; + } + } + + Class clazz = GenericArrayTypeTester.class; + Method foo = clazz.getMethod("foo"); + Type typeMybatis = TypeParameterResolver.resolveReturnType(foo, clazz); + Type typeJdk = foo.getGenericReturnType(); + + assertTrue(typeJdk instanceof GenericArrayType && !(typeJdk instanceof TypeParameterResolver.GenericArrayTypeImpl)); + assertTrue(typeMybatis instanceof TypeParameterResolver.GenericArrayTypeImpl); + assertEquals(typeMybatis.equals(typeJdk), typeJdk.equals(typeMybatis)); } @Test From ead60a5a4312a2be08dbbdd74ada96f2df1e066d Mon Sep 17 00:00:00 2001 From: guanchengang <162052809@qq.com> Date: Sun, 21 Sep 2025 12:17:04 +0800 Subject: [PATCH 08/11] change assertEquals to two assertTrue --- .../ibatis/reflection/TypeParameterResolverTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index da151b7b8b0..0b91c7ab98d 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -571,7 +571,8 @@ public Entry entry() { assertTrue(typeJdk instanceof ParameterizedType && !(typeJdk instanceof TypeParameterResolver.ParameterizedTypeImpl)); assertTrue(typeMybatis instanceof TypeParameterResolver.ParameterizedTypeImpl); - assertEquals(typeMybatis.equals(typeJdk), typeJdk.equals(typeMybatis)); + assertTrue(typeJdk.equals(typeMybatis)); + assertTrue(typeMybatis.equals(typeJdk)); } @Test @@ -592,7 +593,8 @@ public List foo() { assertTrue(wildcardJdk instanceof WildcardType && !(wildcardJdk instanceof TypeParameterResolver.WildcardTypeImpl)); assertTrue(wildcardMybatis instanceof TypeParameterResolver.WildcardTypeImpl); - assertEquals(wildcardMybatis.equals(wildcardJdk), wildcardJdk.equals(wildcardMybatis)); + assertTrue(typeJdk.equals(typeMybatis)); + assertTrue(typeMybatis.equals(typeJdk)); } @Test @@ -610,7 +612,8 @@ public List[] foo() { assertTrue(typeJdk instanceof GenericArrayType && !(typeJdk instanceof TypeParameterResolver.GenericArrayTypeImpl)); assertTrue(typeMybatis instanceof TypeParameterResolver.GenericArrayTypeImpl); - assertEquals(typeMybatis.equals(typeJdk), typeJdk.equals(typeMybatis)); + assertTrue(typeJdk.equals(typeMybatis)); + assertTrue(typeMybatis.equals(typeJdk)); } @Test From bed763c8705adb9f4680121c2a50def4c116ad7c Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 28 Sep 2025 04:29:00 +0900 Subject: [PATCH 09/11] Reverted the message change 2nd arg should be clear enough. --- .../org/apache/ibatis/reflection/TypeParameterResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index d6472022d9f..ab3bf9e0079 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -159,7 +159,7 @@ private static Type resolveTypeVar(TypeVariable typeVar, Type srcType, Class< } } else { throw new IllegalArgumentException( - "The srcType(2nd arg) must be Class or ParameterizedType, but was: " + srcType.getClass()); + "The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass()); } if (clazz == declaringClass) { From 54948d88198e87552edf60619a8fa44a5e87b635 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 28 Sep 2025 04:29:56 +0900 Subject: [PATCH 10/11] Resolved compiler warnings --- .../org/apache/ibatis/reflection/TypeParameterResolverTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index 0b91c7ab98d..1b0d0f556ae 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -578,6 +578,7 @@ public Entry entry() { @Test void shouldWildcardTypeBeEqual() throws Exception { class WildcardTypeTester { + @SuppressWarnings("unused") public List foo() { return null; } @@ -600,6 +601,7 @@ public List foo() { @Test void shouldGenericArrayTypeBeEqual() throws Exception { class GenericArrayTypeTester { + @SuppressWarnings("unused") public List[] foo() { return null; } From 06f830ef4b3b198a9645a5140f59e0c07261aba7 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 28 Sep 2025 04:30:30 +0900 Subject: [PATCH 11/11] Formatted by the maven plugin --- .../ibatis/reflection/TypeParameterResolver.java | 5 ++--- .../ibatis/reflection/TypeParameterResolverTest.java | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java index ab3bf9e0079..3b7a70652c4 100644 --- a/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java +++ b/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java @@ -231,9 +231,8 @@ private static ParameterizedType translateParentTypeVars(ParameterizedType srcTy newParentArgs[i] = parentTypeArgs[i]; } } - return noChange - ? parentType - : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); + return noChange ? parentType + : new ParameterizedTypeImpl((Class) parentType.getRawType(), parentType.getOwnerType(), newParentArgs); } private TypeParameterResolver() { diff --git a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java index 1b0d0f556ae..b0a2747f9cb 100644 --- a/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java +++ b/src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java @@ -569,7 +569,8 @@ public Entry entry() { Method method = clazz.getMethod("selectEntry"); Type typeMybatis = TypeParameterResolver.resolveReturnType(method, clazz); - assertTrue(typeJdk instanceof ParameterizedType && !(typeJdk instanceof TypeParameterResolver.ParameterizedTypeImpl)); + assertTrue( + typeJdk instanceof ParameterizedType && !(typeJdk instanceof TypeParameterResolver.ParameterizedTypeImpl)); assertTrue(typeMybatis instanceof TypeParameterResolver.ParameterizedTypeImpl); assertTrue(typeJdk.equals(typeMybatis)); assertTrue(typeMybatis.equals(typeJdk)); @@ -662,12 +663,11 @@ void shouldToStringHandleInnerClass() throws Exception { Type noTypeOuterReturnType = TypeParameterResolver.resolveReturnType(noTypeOuter, innerTesterClass); Type stringTypeOuterReturnType = TypeParameterResolver.resolveReturnType(stringTypeOuter, innerTesterClass); - assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", - fooReturnType.toString()); + assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", fooReturnType.toString()); assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", - noTypeOuterReturnType.toString()); + noTypeOuterReturnType.toString()); assertEquals("org.apache.ibatis.reflection.TypeParameterResolverTest$Outer$Inner", - stringTypeOuterReturnType.toString()); + stringTypeOuterReturnType.toString()); } }