Find the matching @Recover based on the number of parameters and the type of the parameters
This commit is contained in:
@@ -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 <code>@Recover</code> 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<T> implements MethodInvocationRecoverer<T> {
|
||||
|
||||
@@ -55,7 +56,7 @@ public class RecoverAnnotationRecoveryHandler<T> 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<T> 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<T> 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<T> 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<Class<? extends Throwable>, Method> types = new HashMap<Class<? extends Throwable>, Method>();
|
||||
final Method failingMethod = method;
|
||||
|
||||
@@ -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<Integer>(
|
||||
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<Integer>(
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user