From 182da1590821a0b621c8721e325b5bfc17755fec Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 24 Oct 2017 01:01:49 +0200 Subject: [PATCH] BridgeMethodResolver properly resolves interface hierarchies Issue: SPR-16103 --- .../core/BridgeMethodResolver.java | 74 ++++---- .../core/BridgeMethodResolverTests.java | 177 ++++++++++++------ 2 files changed, 160 insertions(+), 91 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java b/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java index e119fef091..a5d6ec0458 100644 --- a/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java +++ b/spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java @@ -138,43 +138,13 @@ public abstract class BridgeMethodResolver { return (method != null && isResolvedTypeMatch(method, candidateMethod, declaringClass)); } - /** - * Searches for the generic {@link Method} declaration whose erased signature - * matches that of the supplied bridge method. - * @throws IllegalStateException if the generic declaration cannot be found - */ - @Nullable - private static Method findGenericDeclaration(Method bridgeMethod) { - // Search parent types for method that has same signature as bridge. - Class superclass = bridgeMethod.getDeclaringClass().getSuperclass(); - while (superclass != null && Object.class != superclass) { - Method method = searchForMatch(superclass, bridgeMethod); - if (method != null && !method.isBridge()) { - return method; - } - superclass = superclass.getSuperclass(); - } - - // Search interfaces. - Class[] interfaces = ClassUtils.getAllInterfacesForClass(bridgeMethod.getDeclaringClass()); - for (Class ifc : interfaces) { - Method method = searchForMatch(ifc, bridgeMethod); - if (method != null && !method.isBridge()) { - return method; - } - } - - return null; - } - /** * Returns {@code true} if the {@link Type} signature of both the supplied * {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method} * are equal after resolving all types against the declaringType, otherwise * returns {@code false}. */ - private static boolean isResolvedTypeMatch( - Method genericMethod, Method candidateMethod, Class declaringClass) { + private static boolean isResolvedTypeMatch(Method genericMethod, Method candidateMethod, Class declaringClass) { Type[] genericParameters = genericMethod.getGenericParameterTypes(); Class[] candidateParameters = candidateMethod.getParameterTypes(); if (genericParameters.length != candidateParameters.length) { @@ -197,6 +167,41 @@ public abstract class BridgeMethodResolver { return true; } + /** + * Searches for the generic {@link Method} declaration whose erased signature + * matches that of the supplied bridge method. + * @throws IllegalStateException if the generic declaration cannot be found + */ + @Nullable + private static Method findGenericDeclaration(Method bridgeMethod) { + // Search parent types for method that has same signature as bridge. + Class superclass = bridgeMethod.getDeclaringClass().getSuperclass(); + while (superclass != null && Object.class != superclass) { + Method method = searchForMatch(superclass, bridgeMethod); + if (method != null && !method.isBridge()) { + return method; + } + superclass = superclass.getSuperclass(); + } + + Class[] interfaces = ClassUtils.getAllInterfacesForClass(bridgeMethod.getDeclaringClass()); + return searchInterfaces(interfaces, bridgeMethod); + } + + @Nullable + private static Method searchInterfaces(Class[] interfaces, Method bridgeMethod) { + for (Class ifc : interfaces) { + Method method = searchForMatch(ifc, bridgeMethod); + if (method != null && !method.isBridge()) { + return method; + } + else { + return searchInterfaces(ifc.getInterfaces(), bridgeMethod); + } + } + return null; + } + /** * If the supplied {@link Class} has a declared {@link Method} whose signature matches * that of the supplied {@link Method}, then this matching {@link Method} is returned, @@ -204,7 +209,12 @@ public abstract class BridgeMethodResolver { */ @Nullable private static Method searchForMatch(Class type, Method bridgeMethod) { - return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes()); + try { + return type.getDeclaredMethod(bridgeMethod.getName(), bridgeMethod.getParameterTypes()); + } + catch (NoSuchMethodException ex) { + return null; + } } /** diff --git a/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java index 0aa4d075cc..f563c0e37e 100644 --- a/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java @@ -303,8 +303,26 @@ public class BridgeMethodResolverTests { assertEquals("findBy", bridgedMethod.getName()); } + @Test // SPR-16103 + public void testClassHierarchy() throws Exception { + doTestHierarchyResolution(FooClass.class); + } + + @Test // SPR-16103 + public void testInterfaceHierarchy() throws Exception { + doTestHierarchyResolution(FooInterface.class); + } + + private void doTestHierarchyResolution(Class clazz) throws Exception { + for (Method method : clazz.getDeclaredMethods()){ + Method bridged = BridgeMethodResolver.findBridgedMethod(method); + Method expected = clazz.getMethod("test", FooEntity.class); + assertEquals(expected, bridged); + } + } + - public static interface Foo { + public interface Foo { void someMethod(T theArg, Object otherArg); @@ -355,7 +373,7 @@ public class BridgeMethodResolverTests { } - public static interface Adder { + public interface Adder { void add(T item); } @@ -404,7 +422,7 @@ public class BridgeMethodResolverTests { } - public static interface Boo { + public interface Boo { void foo(E e); @@ -426,17 +444,15 @@ public class BridgeMethodResolverTests { } - public static interface Settings { - + public interface Settings { } - public static interface ConcreteSettings extends Settings { - + public interface ConcreteSettings extends Settings { } - public static interface Dao { + public interface Dao { T load(); @@ -444,15 +460,14 @@ public class BridgeMethodResolverTests { } - public static interface SettingsDao extends Dao { + public interface SettingsDao extends Dao { @Override T load(); } - public static interface ConcreteSettingsDao extends - SettingsDao { + public interface ConcreteSettingsDao extends SettingsDao { @Override String loadFromParent(); @@ -470,7 +485,7 @@ public class BridgeMethodResolverTests { this.otherObject = otherObject; } - //@Transactional(readOnly = true) + // @Transactional(readOnly = true) @Override public S loadFromParent() { return otherObject; @@ -485,7 +500,7 @@ public class BridgeMethodResolverTests { super(object, "From Parent"); } - //@Transactional(readOnly = true) + // @Transactional(readOnly = true) @Override public ConcreteSettings load() { return super.object; @@ -493,7 +508,7 @@ public class BridgeMethodResolverTests { } - public static interface Bounded { + public interface Bounded { boolean boundedOperation(E e); } @@ -517,7 +532,7 @@ public class BridgeMethodResolverTests { } - public static interface GenericParameter { + public interface GenericParameter { T getFor(Class cls); } @@ -656,7 +671,7 @@ public class BridgeMethodResolverTests { } - public static interface Event { + public interface Event { int getPriority(); } @@ -686,24 +701,19 @@ public class BridgeMethodResolverTests { } - public static interface UserInitiatedEvent { - - //public Session getInitiatorSession(); + public interface UserInitiatedEvent { } - public static abstract class BaseUserInitiatedEvent extends GenericEvent implements - UserInitiatedEvent { - + public static abstract class BaseUserInitiatedEvent extends GenericEvent implements UserInitiatedEvent { } public static class MessageEvent extends BaseUserInitiatedEvent { - } - public static interface Channel { + public interface Channel { void send(E event); @@ -713,29 +723,27 @@ public class BridgeMethodResolverTests { } - public static interface Broadcaster { + public interface Broadcaster { } - public static interface EventBroadcaster extends Broadcaster { + public interface EventBroadcaster extends Broadcaster { - public void subscribe(); + void subscribe(); - public void unsubscribe(); + void unsubscribe(); - public void setChannel(Channel channel); + void setChannel(Channel channel); } public static class GenericBroadcasterImpl implements Broadcaster { - } @SuppressWarnings({ "unused", "unchecked" }) - public static abstract class GenericEventBroadcasterImpl extends - GenericBroadcasterImpl - implements EventBroadcaster { + public static abstract class GenericEventBroadcasterImpl + extends GenericBroadcasterImpl implements EventBroadcaster { private Class[] subscribingEvents; @@ -761,27 +769,24 @@ public class BridgeMethodResolverTests { @Override public void subscribe() { - } @Override public void unsubscribe() { - } public GenericEventBroadcasterImpl(Class... events) { - } } - public static interface Receiver { + public interface Receiver { void receive(E event); } - public static interface MessageBroadcaster extends Receiver { + public interface MessageBroadcaster extends Receiver { } @@ -835,7 +840,7 @@ public class BridgeMethodResolverTests { // SPR-2454 Test Classes //----------------------------- - public static interface SimpleGenericRepository { + public interface SimpleGenericRepository { public Class getPersistentClass(); @@ -851,7 +856,7 @@ public class BridgeMethodResolverTests { } - public static interface RepositoryRegistry { + public interface RepositoryRegistry { SimpleGenericRepository getFor(Class entityType); } @@ -883,7 +888,7 @@ public class BridgeMethodResolverTests { } - public static interface ConvenientGenericRepository + public interface ConvenientGenericRepository extends SimpleGenericRepository { T findById(ID id, boolean lock); @@ -977,7 +982,7 @@ public class BridgeMethodResolverTests { // SPR-2603 classes //------------------- - public static interface Homer { + public interface Homer { void foo(E e); } @@ -1002,18 +1007,17 @@ public class BridgeMethodResolverTests { } - public static interface GenericDao { + public interface GenericDao { - public void saveOrUpdate(T t); + void saveOrUpdate(T t); } - public static interface ConvenienceGenericDao extends GenericDao { + public interface ConvenienceGenericDao extends GenericDao { } - public static class GenericSqlMapDao implements - ConvenienceGenericDao { + public static class GenericSqlMapDao implements ConvenienceGenericDao { @Override public void saveOrUpdate(T t) { @@ -1022,8 +1026,7 @@ public class BridgeMethodResolverTests { } - public static class GenericSqlMapIntegerDao extends - GenericSqlMapDao { + public static class GenericSqlMapIntegerDao extends GenericSqlMapDao { @Override public void saveOrUpdate(T t) { @@ -1039,12 +1042,12 @@ public class BridgeMethodResolverTests { } - public static interface UserDao { + public interface UserDao { - //@Transactional + // @Transactional void save(User user); - //@Transactional + // @Transactional void save(Permission perm); } @@ -1071,8 +1074,9 @@ public class BridgeMethodResolverTests { } - public static interface DaoInterface { - T get(P id); + public interface DaoInterface { + + T get(P id); } @@ -1125,13 +1129,13 @@ public class BridgeMethodResolverTests { } - public static interface MegaReceiver { + public interface MegaReceiver { void receive(E event); } - public static interface MegaMessageProducer extends MegaReceiver { + public interface MegaMessageProducer extends MegaReceiver { } @@ -1169,7 +1173,7 @@ public class BridgeMethodResolverTests { } - public static interface IGenericInterface { + public interface IGenericInterface { void doSomething(final D domainObject, final T value); } @@ -1234,7 +1238,7 @@ public class BridgeMethodResolverTests { // SPR-3534 classes //------------------- - public static interface SearchProvider { + public interface SearchProvider { Collection findBy(CONDITIONS_TYPE conditions); } @@ -1244,7 +1248,7 @@ public class BridgeMethodResolverTests { } - public static interface IExternalMessageProvider> + public interface IExternalMessageProvider> extends SearchProvider { } @@ -1287,4 +1291,59 @@ public class BridgeMethodResolverTests { } } + + //------------------- + // SPR-16103 classes + //------------------- + + public static abstract class BaseEntity { + + private String id; + } + + public static class FooEntity extends BaseEntity { + + private String name; + } + + public static class BaseClass { + + public S test(S T) { + return null; + } + } + + public static class EntityClass extends BaseClass { + + @Override + public S test(S T) { + return null; + } + } + + public static class FooClass extends EntityClass { + + @Override + public S test(S T) { + return null; + } + } + + public interface BaseInterface { + + S test(S T); + } + + public interface EntityInterface extends BaseInterface { + + @Override + S test(S T); + } + + public interface FooInterface extends EntityInterface { + + @Override + S test(S T); + } + } -- GitLab