From ddea8eda8f48a2bbbd33c070fd9c08daa529c693 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 20 Apr 2012 13:55:34 +0200 Subject: [PATCH] DATACMNS-157 - Query method lookup now only returns most specific method for overridden methods. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supposed you have a base repository interface declaring a method: interface BaseRepository extends Repository { T myGenericMethod(); } as well as a concrete repository redeclaring this method to annotate a query on it: interface ConcreteRepository extends BaseRepository { @Query("…") User myGenericMethod() } Until now we both returned the intermediate method as well as the concrete one which might cause failures as in this case a query derivation would be attempted for the intermediate method which will fail for obvious reasons. The fix now starts with looking up the most specific method when iterating over the repository's methods which causes the intermediate method to be skipped in case it was overridden. --- .../support/DefaultRepositoryInformation.java | 2 ++ ...DefaultRepositoryInformationUnitTests.java | 21 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java index 8f524847a..affad102c 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java @@ -31,6 +31,7 @@ import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * Default implementation of {@link RepositoryInformation}. @@ -155,6 +156,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements Set result = new HashSet(); for (Method method : getRepositoryInterface().getMethods()) { + method = ClassUtils.getMostSpecificMethod(method, getRepositoryInterface()); if (!isCustomMethod(method) && !isBaseClassMethod(method)) { result.add(method); } diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java index fb4b43987..51b8c6f72 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryInformationUnitTests.java @@ -8,7 +8,6 @@ import java.lang.reflect.Method; import java.util.List; import org.hamcrest.Matcher; -import org.hamcrest.Matchers; import org.hamcrest.collection.IsEmptyIterable; import org.junit.Test; import org.junit.runner.RunWith; @@ -126,7 +125,21 @@ public class DefaultRepositoryInformationUnitTests { assertThat(queryMethods, not(hasItem(saveMethod))); assertThat(queryMethods, not(hasItem(deleteMethod))); - assertThat(queryMethods, is(Matchers. iterableWithSize(2))); + } + + @Test + public void onlyReturnsMostConcreteQueryMethod() throws Exception { + + RepositoryMetadata metadata = new DefaultRepositoryMetadata(ConcreteRepository.class); + RepositoryInformation information = new DefaultRepositoryInformation(metadata, CrudRepository.class, null); + + Method intermediateMethod = BaseRepository.class.getMethod("genericMethodToOverride", String.class); + Method concreteMethod = ConcreteRepository.class.getMethod("genericMethodToOverride", String.class); + + Iterable queryMethods = information.getQueryMethods(); + + assertThat(queryMethods, hasItem(concreteMethod)); + assertThat(queryMethods, not(hasItem(intermediateMethod))); } private Method getMethodFrom(Class type, String name) { @@ -167,6 +180,8 @@ public class DefaultRepositoryInformationUnitTests { S findBySomething(String something); + S genericMethodToOverride(String something); + K save(K entity); void delete(S entity); @@ -175,6 +190,8 @@ public class DefaultRepositoryInformationUnitTests { interface ConcreteRepository extends BaseRepository { User findBySomethingDifferent(String somethingDifferent); + + User genericMethodToOverride(String something); } interface ReadOnlyRepository extends Repository {