diff --git a/src/main/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandler.java b/src/main/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandler.java
index 250d49e..fd2db51 100644
--- a/src/main/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandler.java
+++ b/src/main/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandler.java
@@ -16,10 +16,6 @@
package org.springframework.retry.annotation;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
import org.springframework.classify.SubclassClassifier;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.retry.ExhaustedRetryException;
@@ -27,6 +23,10 @@ import org.springframework.retry.interceptor.MethodInvocationRecoverer;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* A recoverer for method invocations based on the @Recover annotation. A
* suitable recovery method is one with a Throwable type as the first parameter and the
@@ -37,10 +37,11 @@ import org.springframework.util.ReflectionUtils.MethodCallback;
* class hierarchy is chosen, so for instance if an IllegalArgumentException is being
* handled and there is a method whose first argument is RuntimeException, then it will be
* preferred over a method whose first argument is Throwable.
- *
+ *
* @author Dave Syer
* @author Josh Long
* @author Aldo Sinanaj
+ * @author Randell Callahan
*/
public class RecoverAnnotationRecoveryHandler implements MethodInvocationRecoverer {
@@ -55,7 +56,7 @@ public class RecoverAnnotationRecoveryHandler implements MethodInvocationReco
@Override
public T recover(Object[] args, Throwable cause) {
- Method method = findClosestMatch(cause.getClass());
+ Method method = findClosestMatch(args, cause.getClass());
if (method == null) {
throw new ExhaustedRetryException("Cannot locate recovery method", cause);
}
@@ -75,7 +76,7 @@ public class RecoverAnnotationRecoveryHandler implements MethodInvocationReco
}
}
- private Method findClosestMatch(Class extends Throwable> cause) {
+ private Method findClosestMatch(Object[] args, Class extends Throwable> cause) {
int min = Integer.MAX_VALUE;
Method result = null;
for (Method method : methods.keySet()) {
@@ -90,6 +91,13 @@ public class RecoverAnnotationRecoveryHandler implements MethodInvocationReco
min = distance;
result = method;
}
+ else if (distance == min) {
+ boolean parametersMatch = compareParameters( args, meta.getArgCount(),
+ method.getParameterTypes() );
+ if (parametersMatch) {
+ result = method;
+ }
+ }
}
}
return result;
@@ -106,6 +114,22 @@ public class RecoverAnnotationRecoveryHandler implements MethodInvocationReco
return result;
}
+ private boolean compareParameters(Object[] args, int argCount, Class>[] parameterTypes) {
+ if (argCount == (args.length + 1)) {
+ int startingIndex = 0;
+ if (parameterTypes.length > 0 && parameterTypes[0] == Throwable.class) {
+ startingIndex = 1;
+ }
+ for (int i = startingIndex; i < parameterTypes.length; i++) {
+ if (parameterTypes[i] != args[i-1].getClass()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
private void init(Object target, Method method) {
final Map, Method> types = new HashMap, Method>();
final Method failingMethod = method;
diff --git a/src/test/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandlerTests.java b/src/test/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandlerTests.java
index 29b7c4b..5b4da88 100644
--- a/src/test/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandlerTests.java
+++ b/src/test/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandlerTests.java
@@ -22,9 +22,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.retry.ExhaustedRetryException;
-import org.springframework.retry.annotation.Recover;
-import org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler;
-import org.springframework.retry.annotation.Retryable;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
@@ -32,6 +29,7 @@ import java.lang.reflect.Method;
/**
* @author Dave Syer
* @author Aldo Sinanaj
+ * @author Randell Callahan
*/
public class RecoverAnnotationRecoveryHandlerTests {
@@ -116,6 +114,28 @@ public class RecoverAnnotationRecoveryHandlerTests {
}
+ @Test
+ public void multipleQualifyingRecoverMethods (){
+ Method foo = ReflectionUtils.findMethod(MultipleQualifyingRecovers.class,
+ "foo", String.class);
+ RecoverAnnotationRecoveryHandler> handler = new RecoverAnnotationRecoveryHandler(
+ new MultipleQualifyingRecovers(), foo);
+ assertEquals(1,
+ handler.recover(new Object[] { "Randell" }, new RuntimeException("Planned")));
+
+ }
+
+ @Test
+ public void multipleQualifyingRecoverMethodsReOrdered (){
+ Method foo = ReflectionUtils.findMethod(MultipleQualifyingRecoversReOrdered.class,
+ "foo", String.class);
+ RecoverAnnotationRecoveryHandler> handler = new RecoverAnnotationRecoveryHandler(
+ new MultipleQualifyingRecoversReOrdered(), foo);
+ assertEquals(3,
+ handler.recover(new Object[] { "Randell" }, new RuntimeException("Planned")));
+
+ }
+
private static class InAccessibleRecover {
@Retryable
@@ -232,4 +252,52 @@ public class RecoverAnnotationRecoveryHandlerTests {
}
+ protected static class MultipleQualifyingRecovers {
+
+ @Retryable
+ public int foo(String name) {
+ return 0;
+ }
+
+ @Recover
+ public int fooRecover(Throwable e, String name) {
+ return 1;
+ }
+
+ @Recover
+ public int fooRecover(Throwable e) {
+ return 2;
+ }
+
+ @Recover
+ public int barRecover(Throwable e, int number) {
+ return 3;
+ }
+
+ }
+
+ protected static class MultipleQualifyingRecoversReOrdered {
+
+ @Retryable
+ public int foo(String name) {
+ return 0;
+ }
+
+ @Recover
+ public int fooRecover(Throwable e) {
+ return 1;
+ }
+
+ @Recover
+ public int barRecover(Throwable e, int number) {
+ return 2;
+ }
+
+ @Recover
+ public int fooRecover(Throwable e, String name) {
+ return 3;
+ }
+
+ }
+
}