Skip to content

Commit a60f3a9

Browse files
committed
fixes #1260 When scanning super types, replace type variables with actual types.
As a side effect, it now returns more accurate result when involving type bounds. See the change in the existing test case.
1 parent c204857 commit a60f3a9

File tree

2 files changed

+58
-27
lines changed

2 files changed

+58
-27
lines changed

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

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2016 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -170,39 +170,48 @@ private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<
170170
}
171171

172172
private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
173-
Type result = null;
174173
if (superclass instanceof ParameterizedType) {
175174
ParameterizedType parentAsType = (ParameterizedType) superclass;
176175
Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
176+
TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
177+
if (srcType instanceof ParameterizedType) {
178+
parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
179+
}
177180
if (declaringClass == parentAsClass) {
178-
Type[] typeArgs = parentAsType.getActualTypeArguments();
179-
TypeVariable<?>[] declaredTypeVars = declaringClass.getTypeParameters();
180-
for (int i = 0; i < declaredTypeVars.length; i++) {
181-
if (declaredTypeVars[i] == typeVar) {
182-
if (typeArgs[i] instanceof TypeVariable) {
183-
TypeVariable<?>[] typeParams = clazz.getTypeParameters();
184-
for (int j = 0; j < typeParams.length; j++) {
185-
if (typeParams[j] == typeArgs[i]) {
186-
if (srcType instanceof ParameterizedType) {
187-
result = ((ParameterizedType) srcType).getActualTypeArguments()[j];
188-
}
189-
break;
190-
}
191-
}
192-
} else {
193-
result = typeArgs[i];
194-
}
181+
for (int i = 0; i < parentTypeVars.length; i++) {
182+
if (typeVar == parentTypeVars[i]) {
183+
return parentAsType.getActualTypeArguments()[i];
195184
}
196185
}
197-
} else if (declaringClass.isAssignableFrom(parentAsClass)) {
198-
result = resolveTypeVar(typeVar, parentAsType, declaringClass);
199186
}
200-
} else if (superclass instanceof Class) {
201-
if (declaringClass.isAssignableFrom((Class<?>) superclass)) {
202-
result = resolveTypeVar(typeVar, superclass, declaringClass);
187+
if (declaringClass.isAssignableFrom(parentAsClass)) {
188+
return resolveTypeVar(typeVar, parentAsType, declaringClass);
203189
}
190+
} else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
191+
return resolveTypeVar(typeVar, superclass, declaringClass);
204192
}
205-
return result;
193+
return null;
194+
}
195+
196+
private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
197+
Type[] parentTypeArgs = parentType.getActualTypeArguments();
198+
Type[] srcTypeArgs = srcType.getActualTypeArguments();
199+
TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
200+
Type[] newParentArgs = new Type[parentTypeArgs.length];
201+
boolean noChange = true;
202+
for (int i = 0; i < parentTypeArgs.length; i++) {
203+
if (parentTypeArgs[i] instanceof TypeVariable) {
204+
for (int j = 0; j < srcTypeVars.length; j++) {
205+
if (srcTypeVars[j] == parentTypeArgs[i]) {
206+
noChange = false;
207+
newParentArgs[i] = srcTypeArgs[j];
208+
}
209+
}
210+
} else {
211+
newParentArgs[i] = parentTypeArgs[i];
212+
}
213+
}
214+
return noChange ? parentType : new ParameterizedTypeImpl((Class<?>)parentType.getRawType(), null, newParentArgs);
206215
}
207216

208217
private TypeParameterResolver() {

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2016 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -135,7 +135,11 @@ public void testReturn_SimpleTypeVar() throws Exception {
135135
Class<?> clazz = Level1Mapper.class;
136136
Method method = clazz.getMethod("simpleSelectTypeVar");
137137
Type result = TypeParameterResolver.resolveReturnType(method, clazz);
138-
assertEquals(Object.class, result);
138+
assertTrue(result instanceof ParameterizedType);
139+
ParameterizedType paramType = (ParameterizedType) result;
140+
assertEquals(Calculator.class, paramType.getRawType());
141+
assertEquals(1, paramType.getActualTypeArguments().length);
142+
assertTrue(paramType.getActualTypeArguments()[0] instanceof WildcardType);
139143
}
140144

141145
@Test
@@ -402,4 +406,22 @@ public void setKey2(T key2) {
402406
Method setter2 = clazz.getMethod("setKey2", Key.class);
403407
assertEquals(Key.class, TypeParameterResolver.resolveParamTypes(setter2, clazz)[0]);
404408
}
409+
410+
@Test
411+
public void testDeepHierarchy() throws Exception {
412+
@SuppressWarnings("unused")
413+
abstract class A<S> {
414+
protected S id;
415+
public S getId() { return this.id;}
416+
public void setId(S id) {this.id = id;}
417+
}
418+
abstract class B<T> extends A<T> {}
419+
abstract class C<U> extends B<U> {}
420+
class D extends C<Integer> {}
421+
Class<?> clazz = D.class;
422+
Method method = clazz.getMethod("getId");
423+
assertEquals(Integer.class, TypeParameterResolver.resolveReturnType(method, clazz));
424+
Field field = A.class.getDeclaredField("id");
425+
assertEquals(Integer.class, TypeParameterResolver.resolveFieldType(field, clazz));
426+
}
405427
}

0 commit comments

Comments
 (0)