diff --git a/spring-data-mock-sample-jpa/pom.xml b/spring-data-mock-sample-jpa/pom.xml index 13814e9e..76887729 100644 --- a/spring-data-mock-sample-jpa/pom.xml +++ b/spring-data-mock-sample-jpa/pom.xml @@ -35,7 +35,7 @@ 1.12.1.RELEASE 1.10.1.RELEASE 1.0.2 - 1.1.4 + 1.1.5 6.9.6 1.3 UTF-8 diff --git a/spring-data-mock/pom.xml b/spring-data-mock/pom.xml index b34c88eb..8461fba2 100644 --- a/spring-data-mock/pom.xml +++ b/spring-data-mock/pom.xml @@ -27,7 +27,7 @@ com.mmnaseri.utils spring-data-mock - 1.1.4 + 1.1.5 Spring Data Mock A framework for mocking Spring Data repositories diff --git a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolver.java b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolver.java index ee6047a3..52bc8e70 100644 --- a/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolver.java +++ b/spring-data-mock/src/main/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolver.java @@ -11,6 +11,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.LinkedList; import java.util.List; /** @@ -50,9 +51,12 @@ public SignatureDataOperationResolver(List> mappings) { return null; } - private static Method findMethod(Class type, String name, Class... parameterTypes) { + private Method findMethod(Class type, String name, Class... parameterTypes) { log.debug("Attempting to look for the actual declaration of the method named '" + name + "' with parameter types " + Arrays.toString(parameterTypes) + " on the child type " + type); Class searchType = type; + + List matchingMethods = new LinkedList<>(); + while (searchType != null) { log.trace("Looking at type " + type + " for method " + name); final Method[] methods = searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods(); @@ -61,19 +65,56 @@ private static Method findMethod(Class type, String name, Class... paramet boolean matches = true; for (int i = 0; i < parameterTypes.length; i++) { final Class parameterType = parameterTypes[i]; - if (!PropertyUtils.getTypeOf(method.getParameterTypes()[i]).isAssignableFrom(PropertyUtils.getTypeOf(parameterType))) { + if (!doParamsMatchByAssignability(method.getParameterTypes()[i], PropertyUtils.getTypeOf(parameterType))) { matches = false; break; } } if (matches) { - return method; + matchingMethods.add(method); } } } searchType = searchType.getSuperclass(); } + + if (matchingMethods.size() == 0) { + return null; + } else if (matchingMethods.size() == 1) { + return matchingMethods.get(0); + } else { + Method method = exactlyMatchingMethod(matchingMethods, parameterTypes); + if (method == null) { + return matchingMethods.get(matchingMethods.size() - 1); + } else { + return method; + } + } + } + + private Method exactlyMatchingMethod(List methods, Class[] parameterTypes) { + for (Method method : methods) { + boolean matches = true; + for (int i = 0; i < parameterTypes.length; i++) { + final Class parameterType = parameterTypes[i]; + if (!(doParamsMatchExactly(method.getParameterTypes()[i], PropertyUtils.getTypeOf(parameterType)))) { + matches = false; + break; + } + } + if (matches) { + return method; + } + } return null; } + protected boolean doParamsMatchByAssignability(Class thisParam, Class thatParam) { + return PropertyUtils.getTypeOf(thisParam).isAssignableFrom(thatParam); + } + + + protected boolean doParamsMatchExactly(Class thisParam, Class thatParam) { + return thisParam.getCanonicalName().equals(thatParam.getCanonicalName()); + } } diff --git a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolverTest.java b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolverTest.java index 7c11ab8c..418e1bff 100644 --- a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolverTest.java +++ b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/proxy/impl/resolvers/SignatureDataOperationResolverTest.java @@ -8,7 +8,9 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -30,6 +32,31 @@ public void setUp() throws Exception { resolver = new SignatureDataOperationResolver(mappings); } + @Test + public void testWeResolveTheCorrectMethod_whenMethodWithObjectParam_comesFirstInMethodList() throws Exception { + Method method = ProxiedClass.class.getMethod("somethingToAnObject", Iterable.class); + final DataStoreOperation operation = resolver.resolve(method); + + assertThat(operation, is(notNullValue())); + assertThat(operation, is(instanceOf(MethodInvocationDataStoreOperation.class))); + final MethodInvocationDataStoreOperation invocationOperation = (MethodInvocationDataStoreOperation) operation; + assertThat(invocationOperation.getInstance(), is(instanceOf(SuperInterface.class))); + assertThat(invocationOperation.getMethod(), is(SuperInterface.class.getMethod("somethingToAnObject", Iterable.class))); + } + + + @Test + public void testWeResolveTheCorrectMethod_whenMethodWithObjectParam_comesFirstInMethodList_andNotAnExactMatch() throws Exception { + Method method = ProxiedClass.class.getMethod("somethingToAnObject", Collection.class); + final DataStoreOperation operation = resolver.resolve(method); + + assertThat(operation, is(notNullValue())); + assertThat(operation, is(instanceOf(MethodInvocationDataStoreOperation.class))); + final MethodInvocationDataStoreOperation invocationOperation = (MethodInvocationDataStoreOperation) operation; + assertThat(invocationOperation.getInstance(), is(instanceOf(SuperInterface.class))); + assertThat(invocationOperation.getMethod(), is(SuperInterface.class.getMethod("somethingToAnObject", Iterable.class))); + } + @Test public void testLookingForExactMatchViaInterface() throws Exception { final DataStoreOperation operation = resolver.resolve(ProxiedClass.class.getMethod("saySomething", String.class, Double.class)); diff --git a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/ProxiedClass.java b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/ProxiedClass.java index 56f126e3..4f207801 100644 --- a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/ProxiedClass.java +++ b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/ProxiedClass.java @@ -1,5 +1,7 @@ package com.mmnaseri.utils.spring.data.sample.usecases.proxy.resolvers; +import java.util.Collection; + /** * @author Milad Naseri (mmnaseri@programmer.net) * @since 1.0 (4/12/16, 6:36 PM) @@ -16,4 +18,8 @@ public interface ProxiedClass { void doSomething(); + void somethingToAnObject(Iterable iterable); + + void somethingToAnObject(Collection iterable); + } diff --git a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterface.java b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterface.java index d7b5fa4f..5ac328a7 100644 --- a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterface.java +++ b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterface.java @@ -6,8 +6,14 @@ */ public interface SuperInterface { + void somethingToAnObject(Object object); + + void somethingToAnObject(Iterable iterable); + + void saySomething(CharSequence sequence, Double number); void doSomething(); + } diff --git a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterfaceImpl.java b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterfaceImpl.java index 11876f3e..6928dc99 100644 --- a/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterfaceImpl.java +++ b/spring-data-mock/src/test/java/com/mmnaseri/utils/spring/data/sample/usecases/proxy/resolvers/SuperInterfaceImpl.java @@ -6,6 +6,16 @@ */ public class SuperInterfaceImpl implements SuperInterface { + @Override + public void somethingToAnObject(Object object) { + + } + + @Override + public void somethingToAnObject(Iterable iterable) { + + } + @Override public void saySomething(CharSequence sequence, Double number) { @@ -15,4 +25,5 @@ public void saySomething(CharSequence sequence, Double number) { public void doSomething() { } + }