Skip to content

Commit 1f78ab8

Browse files
committed
optimize TypeParameterResolver
1 parent 55832eb commit 1f78ab8

File tree

2 files changed

+97
-14
lines changed

2 files changed

+97
-14
lines changed

src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,10 @@ private static Type resolveGenericArrayType(GenericArrayType genericArrayType, T
129129
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType,
130130
Class<?> declaringClass) {
131131
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
132+
Type ownerType = parameterizedType.getOwnerType();
132133
Type[] typeArgs = parameterizedType.getActualTypeArguments();
133134
Type[] args = resolveTypes(typeArgs, srcType, declaringClass);
134-
return new ParameterizedTypeImpl(rawType, null, args);
135+
return new ParameterizedTypeImpl(rawType, ownerType, args);
135136
}
136137

137138
private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
@@ -158,7 +159,7 @@ private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<
158159
}
159160
} else {
160161
throw new IllegalArgumentException(
161-
"The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
162+
"The srcType(2nd arg) must be Class or ParameterizedType, but was: " + srcType.getClass());
162163
}
163164

164165
if (clazz == declaringClass) {
@@ -198,7 +199,7 @@ private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<
198199
for (int i = 0; i < parentTypeVars.length; i++) {
199200
if (typeVar.equals(parentTypeVars[i])) {
200201
Type actualType = parentAsType.getActualTypeArguments()[i];
201-
return actualType instanceof TypeVariable<?> ? Object.class : actualType;
202+
return actualType instanceof TypeVariable<?> ? ((TypeVariable<?>) actualType).getBounds()[0] : actualType;
202203
}
203204
}
204205
}
@@ -230,7 +231,40 @@ private static ParameterizedType translateParentTypeVars(ParameterizedType srcTy
230231
newParentArgs[i] = parentTypeArgs[i];
231232
}
232233
}
233-
return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
234+
if (noChange && !(parentType instanceof ParameterizedTypeImpl)) noChange = false;
235+
return noChange
236+
? parentType
237+
: new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), parentType.getOwnerType(), newParentArgs);
238+
}
239+
240+
private static Type canonicalize(Type type) {
241+
if (type instanceof ParameterizedType) {
242+
ParameterizedType p = (ParameterizedType) type;
243+
return new ParameterizedTypeImpl((Class<?>) p.getRawType(), p.getOwnerType(), p.getActualTypeArguments());
244+
}
245+
else if (type instanceof GenericArrayType) {
246+
GenericArrayType g = (GenericArrayType) type;
247+
return new GenericArrayTypeImpl(g.getGenericComponentType());
248+
}
249+
else if (type instanceof WildcardType) {
250+
WildcardType w = (WildcardType) type;
251+
return new WildcardTypeImpl(w.getLowerBounds(), w.getUpperBounds());
252+
}
253+
else {
254+
return type;
255+
}
256+
}
257+
258+
private static Type[] canonicalizeTypes(Type[] types) {
259+
if (types == null || types.length == 0) {
260+
return new Type[0];
261+
}
262+
int length = types.length;
263+
Type[] canonicalizedTypes = new Type[length];
264+
for (int i = 0; i < length; i++) {
265+
canonicalizedTypes[i] = canonicalize(types[i]);
266+
}
267+
return canonicalizedTypes;
234268
}
235269

236270
private TypeParameterResolver() {
@@ -244,11 +278,11 @@ static class ParameterizedTypeImpl implements ParameterizedType {
244278

245279
private final Type[] actualTypeArguments;
246280

247-
public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
281+
ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
248282
super();
249-
this.rawType = rawType;
250-
this.ownerType = ownerType;
251-
this.actualTypeArguments = actualTypeArguments;
283+
this.rawType = (Class<?>) canonicalize(rawType);
284+
this.ownerType = canonicalize(ownerType);
285+
this.actualTypeArguments = canonicalizeTypes(actualTypeArguments);
252286
}
253287

254288
@Override
@@ -283,7 +317,21 @@ public boolean equals(Object obj) {
283317

284318
@Override
285319
public String toString() {
286-
StringBuilder s = new StringBuilder().append(rawType.getName()).append("<");
320+
StringBuilder s = new StringBuilder();
321+
if (ownerType != null) {
322+
s.append(ownerType.getTypeName()).append("$");
323+
if (ownerType instanceof ParameterizedTypeImpl) {
324+
// remove prefixes that do not contain generic information
325+
s.append(
326+
rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", ""));
327+
}
328+
else {
329+
s.append(rawType.getSimpleName());
330+
}
331+
} else {
332+
s.append(rawType.getName());
333+
}
334+
s.append("<");
287335
for (int i = 0; i < actualTypeArguments.length; i++) {
288336
if (i > 0) {
289337
s.append(", ");
@@ -301,8 +349,8 @@ static class WildcardTypeImpl implements WildcardType {
301349

302350
WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
303351
super();
304-
this.lowerBounds = lowerBounds;
305-
this.upperBounds = upperBounds;
352+
this.lowerBounds = canonicalizeTypes(lowerBounds);
353+
this.upperBounds = canonicalizeTypes(upperBounds);
306354
}
307355

308356
@Override
@@ -353,7 +401,7 @@ static class GenericArrayTypeImpl implements GenericArrayType {
353401

354402
GenericArrayTypeImpl(Type genericComponentType) {
355403
super();
356-
this.genericComponentType = genericComponentType;
404+
this.genericComponentType = canonicalize(genericComponentType);
357405
}
358406

359407
@Override
@@ -380,7 +428,7 @@ public boolean equals(Object obj) {
380428

381429
@Override
382430
public String toString() {
383-
return new StringBuilder().append(genericComponentType.toString()).append("[]").toString();
431+
return new StringBuilder().append(genericComponentType.getTypeName()).append("[]").toString();
384432
}
385433
}
386434
}

src/test/java/org/apache/ibatis/reflection/TypeParameterResolverTest.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.junit.jupiter.api.Assertions.assertEquals;
1919
import static org.junit.jupiter.api.Assertions.assertTrue;
2020

21+
import java.io.Serializable;
2122
import java.lang.reflect.Field;
2223
import java.lang.reflect.GenericArrayType;
2324
import java.lang.reflect.Method;
@@ -230,7 +231,6 @@ void returnLv2ArrayOfArray() throws Exception {
230231
Type result = TypeParameterResolver.resolveReturnType(method, clazz);
231232
assertTrue(result instanceof Class);
232233
Class<?> resultClass = (Class<?>) result;
233-
assertTrue(result instanceof Class);
234234
assertTrue(resultClass.isArray());
235235
assertTrue(resultClass.getComponentType().isArray());
236236
assertEquals(String.class, resultClass.getComponentType().getComponentType());
@@ -513,6 +513,41 @@ void shouldResolveInterfaceTypeParamsDeeper() {
513513
assertEquals(String.class, types[0]);
514514
}
515515

516+
@Test
517+
void shouldResolveWildcardTypeInClassDefinition() throws Exception {
518+
class A<T extends Serializable> {
519+
public T foo(T t) {
520+
return t;
521+
}
522+
}
523+
524+
class B<T extends Number> extends A<T> {
525+
526+
}
527+
528+
class C1<T extends Integer> extends B<T> {
529+
530+
}
531+
532+
class C2 extends B<Integer> {
533+
534+
}
535+
536+
class C3 extends B {
537+
538+
}
539+
540+
Method m = A.class.getMethod("foo", Serializable.class);
541+
542+
assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C1.class));
543+
assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(m, C2.class));
544+
assertEquals(Number.class, TypeParameterResolver.resolveReturnType(m, C3.class));
545+
546+
assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C1.class)[0]);
547+
assertEquals(Integer.class, TypeParameterResolver.resolveParamTypes(m, C2.class)[0]);
548+
assertEquals(Number.class, TypeParameterResolver.resolveParamTypes(m, C3.class)[0]);
549+
}
550+
516551
class AA {
517552
}
518553

0 commit comments

Comments
 (0)