Skip to content

optimize TypeParameterResolver #3512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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
Expand Down Expand Up @@ -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(", ");
Expand All @@ -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
Expand Down Expand Up @@ -353,7 +401,7 @@ static class GenericArrayTypeImpl implements GenericArrayType {

GenericArrayTypeImpl(Type genericComponentType) {
super();
this.genericComponentType = genericComponentType;
this.genericComponentType = canonicalize(genericComponentType);
}

@Override
Expand All @@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -513,6 +513,41 @@ void shouldResolveInterfaceTypeParamsDeeper() {
assertEquals(String.class, types[0]);
}

@Test
void shouldResolveWildcardTypeInClassDefinition() throws Exception {
class A<T extends Serializable> {
public T foo(T t) {
return t;
}
}

class B<T extends Number> extends A<T> {

}

class C1<T extends Integer> extends B<T> {

}

class C2 extends B<Integer> {

}

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 {
}

Expand Down