Improve GenericTypeResolver to resolve type variable recursively
Fix GH-24963
This commit is contained in:
parent
4b2e40153a
commit
e788aeb25b
|
@ -67,6 +67,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
|
* @author Yanming Zhou
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
*/
|
*/
|
||||||
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
|
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
|
||||||
|
@ -177,13 +178,14 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
|
if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
|
||||||
if (eventType.hasUnresolvableGenerics()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
|
ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
|
||||||
if (declaredEventType.isAssignableFrom(payloadType)) {
|
if (declaredEventType.isAssignableFrom(payloadType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (payloadType.resolve() == null) {
|
||||||
|
// Always accept such event when the type is erased
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
|
||||||
* @author Rob Harrop
|
* @author Rob Harrop
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Yanming Zhou
|
||||||
* @since 2.5.2
|
* @since 2.5.2
|
||||||
*/
|
*/
|
||||||
public final class GenericTypeResolver {
|
public final class GenericTypeResolver {
|
||||||
|
@ -167,7 +168,7 @@ public final class GenericTypeResolver {
|
||||||
else if (genericType instanceof ParameterizedType parameterizedType) {
|
else if (genericType instanceof ParameterizedType parameterizedType) {
|
||||||
ResolvableType resolvedType = ResolvableType.forType(genericType);
|
ResolvableType resolvedType = ResolvableType.forType(genericType);
|
||||||
if (resolvedType.hasUnresolvableGenerics()) {
|
if (resolvedType.hasUnresolvableGenerics()) {
|
||||||
Class<?>[] generics = new Class<?>[parameterizedType.getActualTypeArguments().length];
|
ResolvableType[] generics = new ResolvableType[parameterizedType.getActualTypeArguments().length];
|
||||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||||
ResolvableType contextType = ResolvableType.forClass(contextClass);
|
ResolvableType contextType = ResolvableType.forClass(contextClass);
|
||||||
for (int i = 0; i < typeArguments.length; i++) {
|
for (int i = 0; i < typeArguments.length; i++) {
|
||||||
|
@ -175,14 +176,17 @@ public final class GenericTypeResolver {
|
||||||
if (typeArgument instanceof TypeVariable<?> typeVariable) {
|
if (typeArgument instanceof TypeVariable<?> typeVariable) {
|
||||||
ResolvableType resolvedTypeArgument = resolveVariable(typeVariable, contextType);
|
ResolvableType resolvedTypeArgument = resolveVariable(typeVariable, contextType);
|
||||||
if (resolvedTypeArgument != ResolvableType.NONE) {
|
if (resolvedTypeArgument != ResolvableType.NONE) {
|
||||||
generics[i] = resolvedTypeArgument.resolve();
|
generics[i] = resolvedTypeArgument;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generics[i] = ResolvableType.forType(typeArgument).resolve();
|
generics[i] = ResolvableType.forType(typeArgument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (typeArgument instanceof ParameterizedType) {
|
||||||
|
generics[i] = ResolvableType.forType(resolveType(typeArgument, contextClass));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
generics[i] = ResolvableType.forType(typeArgument).resolve();
|
generics[i] = ResolvableType.forType(typeArgument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Class<?> rawClass = resolvedType.getRawClass();
|
Class<?> rawClass = resolvedType.getRawClass();
|
||||||
|
|
|
@ -70,6 +70,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Yanming Zhou
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
* @see #forField(Field)
|
* @see #forField(Field)
|
||||||
* @see #forMethodParameter(Method, int)
|
* @see #forMethodParameter(Method, int)
|
||||||
|
@ -572,7 +573,7 @@ public class ResolvableType implements Serializable {
|
||||||
private boolean determineUnresolvableGenerics() {
|
private boolean determineUnresolvableGenerics() {
|
||||||
ResolvableType[] generics = getGenerics();
|
ResolvableType[] generics = getGenerics();
|
||||||
for (ResolvableType generic : generics) {
|
for (ResolvableType generic : generics) {
|
||||||
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) {
|
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds() || generic.hasUnresolvableGenerics()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import static org.springframework.util.ReflectionUtils.findMethod;
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Yanming Zhou
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
class GenericTypeResolverTests {
|
class GenericTypeResolverTests {
|
||||||
|
@ -203,6 +204,13 @@ class GenericTypeResolverTests {
|
||||||
assertThat(resolvedType).isEqualTo(reference.getType());
|
assertThat(resolvedType).isEqualTo(reference.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveNestedTypeVariable() throws Exception {
|
||||||
|
Type resolved = resolveType(ListOfListSupplier.class.getMethod("get").getGenericReturnType(),
|
||||||
|
StringListOfListSupplier.class);
|
||||||
|
assertThat(ResolvableType.forType(resolved).getGeneric(0).getGeneric(0).resolve()).isEqualTo(String.class);
|
||||||
|
}
|
||||||
|
|
||||||
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
||||||
Method method = findMethod(target, methodName, parameterTypes);
|
Method method = findMethod(target, methodName, parameterTypes);
|
||||||
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
||||||
|
@ -382,5 +390,14 @@ class GenericTypeResolverTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface ListOfListSupplier<T> {
|
||||||
|
|
||||||
|
List<List<T>> get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface StringListOfListSupplier extends ListOfListSupplier<String> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ import static org.mockito.Mockito.verify;
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
|
* @author Yanming Zhou
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@ -1314,6 +1315,12 @@ class ResolvableTypeTests {
|
||||||
assertThat(type.hasUnresolvableGenerics()).isTrue();
|
assertThat(type.hasUnresolvableGenerics()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasUnresolvableGenericsWhenNested() throws Exception {
|
||||||
|
ResolvableType type = ResolvableType.forMethodReturnType(ListOfListSupplier.class.getMethod("get"));
|
||||||
|
assertThat(type.hasUnresolvableGenerics()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void spr11219() throws Exception {
|
void spr11219() throws Exception {
|
||||||
ResolvableType type = ResolvableType.forField(BaseProvider.class.getField("stuff"), BaseProvider.class);
|
ResolvableType type = ResolvableType.forField(BaseProvider.class.getField("stuff"), BaseProvider.class);
|
||||||
|
@ -1617,6 +1624,12 @@ class ResolvableTypeTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface ListOfListSupplier<T> {
|
||||||
|
|
||||||
|
List<List<T>> get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class EnclosedInParameterizedType<T> {
|
static class EnclosedInParameterizedType<T> {
|
||||||
|
|
||||||
static class InnerRaw {
|
static class InnerRaw {
|
||||||
|
|
Loading…
Reference in New Issue