Accept assignable match for covariant return type

See gh-35936

(cherry picked from commit df27627516)
This commit is contained in:
Juergen Hoeller
2025-12-08 12:43:35 +01:00
parent 8041a09268
commit ad849fb3a2
2 changed files with 38 additions and 8 deletions
@@ -202,15 +202,15 @@ public final class BridgeMethodResolver {
private static boolean checkResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class<?> clazz) {
// First, compare return type.
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(genericMethod, clazz);
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateMethod.getReturnType()).equals(
ClassUtils.resolvePrimitiveIfNecessary(genericReturnType.toClass()))) {
if (!ClassUtils.resolvePrimitiveIfNecessary(genericReturnType.toClass()).isAssignableFrom(
ClassUtils.resolvePrimitiveIfNecessary(candidateMethod.getReturnType()))) {
return false;
}
Class<?>[] candidateParameters = candidateMethod.getParameterTypes();
for (int i = 0; i < candidateParameters.length; i++) {
ResolvableType genericParameter = ResolvableType.forMethodParameter(genericMethod, i, clazz);
if (!ClassUtils.resolvePrimitiveIfNecessary(candidateParameters[i]).equals(
ClassUtils.resolvePrimitiveIfNecessary(genericParameter.toClass()))) {
if (!ClassUtils.resolvePrimitiveIfNecessary(genericParameter.toClass()).equals(
ClassUtils.resolvePrimitiveIfNecessary(candidateParameters[i]))) {
return false;
}
}
@@ -113,6 +113,14 @@ class BridgeMethodResolverTests {
}
}
@Test
void findBridgedMethodForCovariantReturnType() throws Exception {
Method originalMethod = OuterSubclass.class.getDeclaredMethod("getInner");
for (Method method: OuterSubclass.class.getDeclaredMethods()) {
assertThat(BridgeMethodResolver.findBridgedMethod(method)).isEqualTo(originalMethod);
}
}
@Test
void findBridgedMethodInHierarchyWithBoundedGenerics() throws Exception {
Method originalMethod = Bar.class.getDeclaredMethod("someMethod", Object.class, Object.class);
@@ -425,6 +433,7 @@ class BridgeMethodResolverTests {
public abstract static class SubBar<T extends StringProducer> extends InterBar<T> {
}
public interface StringProducer extends CharSequence {
}
@@ -506,6 +515,31 @@ class BridgeMethodResolverTests {
}
static class Outer {
Inner getInner() {
return new Inner();
}
}
static class OuterSubclass extends Outer {
@Override
InnerSubclass getInner() {
return new InnerSubclass();
}
}
static class Inner {
}
static class InnerSubclass extends Inner {
}
public static class Enclosing<T> {
public class Enclosed<S> {
@@ -899,22 +933,18 @@ class BridgeMethodResolverTests {
public interface MessageBroadcaster extends Receiver<MessageEvent> {
}
public static class RemovedMessageEvent extends MessageEvent {
}
public static class NewMessageEvent extends MessageEvent {
}
public static class ModifiedMessageEvent extends MessageEvent {
}