Skip to content

Commit 85fce38

Browse files
committed
Add generic check for function return type
Fixes: [#215](#215) Signed-off-by: deepesh-verma <[email protected]>
1 parent 868d205 commit 85fce38

File tree

2 files changed

+107
-14
lines changed

2 files changed

+107
-14
lines changed

src/main/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandler.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.retry.annotation;
1818

1919
import java.lang.reflect.Method;
20+
import java.lang.reflect.ParameterizedType;
2021
import java.util.HashMap;
2122
import java.util.Map;
2223

@@ -173,27 +174,34 @@ public void doWith(Method method) throws IllegalArgumentException, IllegalAccess
173174
if (recover == null) {
174175
recover = findAnnotationOnTarget(target, method);
175176
}
176-
if (recover != null && method.getReturnType().isAssignableFrom(failingMethod.getReturnType())) {
177-
Class<?>[] parameterTypes = method.getParameterTypes();
178-
if (parameterTypes.length > 0 && Throwable.class.isAssignableFrom(parameterTypes[0])) {
179-
@SuppressWarnings("unchecked")
180-
Class<? extends Throwable> type = (Class<? extends Throwable>) parameterTypes[0];
181-
types.put(type, method);
182-
RecoverAnnotationRecoveryHandler.this.methods.put(method,
183-
new SimpleMetadata(parameterTypes.length, type));
184-
}
185-
else {
186-
RecoverAnnotationRecoveryHandler.this.classifier.setDefaultValue(method);
187-
RecoverAnnotationRecoveryHandler.this.methods.put(method,
188-
new SimpleMetadata(parameterTypes.length, null));
177+
if (recover != null && failingMethod.getGenericReturnType() instanceof ParameterizedType) {
178+
if (method.getGenericReturnType().equals(failingMethod.getGenericReturnType())) {
179+
putToMethodsMap(method, types);
189180
}
190181
}
182+
else if (recover != null && method.getReturnType().isAssignableFrom(failingMethod.getReturnType())) {
183+
putToMethodsMap(method, types);
184+
}
191185
}
192186
});
193187
this.classifier.setTypeMap(types);
194188
optionallyFilterMethodsBy(failingMethod.getReturnType());
195189
}
196190

191+
private void putToMethodsMap(Method method, Map<Class<? extends Throwable>, Method> types) {
192+
Class<?>[] parameterTypes = method.getParameterTypes();
193+
if (parameterTypes.length > 0 && Throwable.class.isAssignableFrom(parameterTypes[0])) {
194+
@SuppressWarnings("unchecked")
195+
Class<? extends Throwable> type = (Class<? extends Throwable>) parameterTypes[0];
196+
types.put(type, method);
197+
RecoverAnnotationRecoveryHandler.this.methods.put(method, new SimpleMetadata(parameterTypes.length, type));
198+
}
199+
else {
200+
RecoverAnnotationRecoveryHandler.this.classifier.setDefaultValue(method);
201+
RecoverAnnotationRecoveryHandler.this.methods.put(method, new SimpleMetadata(parameterTypes.length, null));
202+
}
203+
}
204+
197205
private Recover findAnnotationOnTarget(Object target, Method method) {
198206
try {
199207
Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());

src/test/java/org/springframework/retry/annotation/RecoverAnnotationRecoveryHandlerTests.java

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,19 @@
1818

1919
import java.lang.reflect.Method;
2020
import java.util.ArrayList;
21+
import java.util.Collections;
2122
import java.util.List;
23+
import java.util.Map;
2224

2325
import org.junit.Rule;
2426
import org.junit.Test;
2527
import org.junit.rules.ExpectedException;
2628

2729
import org.springframework.retry.ExhaustedRetryException;
30+
import org.springframework.util.CollectionUtils;
2831
import org.springframework.util.ReflectionUtils;
2932

30-
import static org.junit.Assert.assertEquals;
33+
import static org.junit.Assert.*;
3134

3235
/**
3336
* @author Dave Syer
@@ -107,6 +110,49 @@ public void parentReturnTypeRecoverMethod() {
107110

108111
}
109112

113+
@Test
114+
public void genericReturnStringValueTypeParentThrowableRecoverMethod() {
115+
116+
RecoverAnnotationRecoveryHandler<?> handler = new RecoverAnnotationRecoveryHandler<List<String>>(
117+
new GenericReturnTypeRecover(),
118+
ReflectionUtils.findMethod(GenericReturnTypeRecover.class, "foo", String.class));
119+
120+
@SuppressWarnings("unchecked")
121+
Map<String, String> recoverResponseMap = (Map<String, String>) handler.recover(new Object[] { "Aldo" },
122+
new RuntimeException("Planned"));
123+
assertFalse(CollectionUtils.isEmpty(recoverResponseMap));
124+
assertEquals("fooRecoverValue1", recoverResponseMap.get("foo"));
125+
}
126+
127+
@Test
128+
public void genericReturnStringValueTypeChildThrowableRecoverMethod() {
129+
130+
RecoverAnnotationRecoveryHandler<?> handler = new RecoverAnnotationRecoveryHandler<List<String>>(
131+
new GenericReturnTypeRecover(),
132+
ReflectionUtils.findMethod(GenericReturnTypeRecover.class, "foo", String.class));
133+
134+
@SuppressWarnings("unchecked")
135+
Map<String, String> recoverResponseMap = (Map<String, String>) handler.recover(new Object[] { "Aldo" },
136+
new IllegalStateException("Planned"));
137+
assertFalse(CollectionUtils.isEmpty(recoverResponseMap));
138+
assertEquals("fooRecoverValue2", recoverResponseMap.get("foo"));
139+
}
140+
141+
@Test
142+
public void genericReturnOneValueTypeRecoverMethod() {
143+
144+
RecoverAnnotationRecoveryHandler<?> handler = new RecoverAnnotationRecoveryHandler<List<String>>(
145+
new GenericReturnTypeRecover(),
146+
ReflectionUtils.findMethod(GenericReturnTypeRecover.class, "bar", String.class));
147+
148+
@SuppressWarnings("unchecked")
149+
Map<String, GenericReturnTypeRecover.One> recoverResponseMap = (Map<String, GenericReturnTypeRecover.One>) handler
150+
.recover(new Object[] { "Aldo" }, new RuntimeException("Planned"));
151+
assertFalse(CollectionUtils.isEmpty(recoverResponseMap));
152+
assertNotNull(recoverResponseMap.get("bar"));
153+
assertEquals("barRecoverValue", recoverResponseMap.get("bar").name);
154+
}
155+
110156
@Test
111157
public void multipleQualifyingRecoverMethods() {
112158
Method foo = ReflectionUtils.findMethod(MultipleQualifyingRecovers.class, "foo", String.class);
@@ -293,6 +339,45 @@ public Number quux(RuntimeException re, String name) {
293339

294340
}
295341

342+
protected static class GenericReturnTypeRecover {
343+
344+
private static class One {
345+
346+
String name;
347+
348+
public One(String name) {
349+
this.name = name;
350+
}
351+
352+
}
353+
354+
@Retryable
355+
public Map<String, String> foo(String name) {
356+
return Collections.singletonMap("foo", "fooValue");
357+
}
358+
359+
@Retryable
360+
public Map<String, One> bar(String name) {
361+
return Collections.singletonMap("bar", new One("barValue"));
362+
}
363+
364+
@Recover
365+
public Map<String, String> fooRecoverRe(RuntimeException re, String name) {
366+
return Collections.singletonMap("foo", "fooRecoverValue1");
367+
}
368+
369+
@Recover
370+
public Map<String, String> fooRecoverIe(IllegalStateException re, String name) {
371+
return Collections.singletonMap("foo", "fooRecoverValue2");
372+
}
373+
374+
@Recover
375+
public Map<String, One> barRecover(RuntimeException re, String name) {
376+
return Collections.singletonMap("bar", new One("barRecoverValue"));
377+
}
378+
379+
}
380+
296381
protected static class MultipleQualifyingRecoversNoThrowable {
297382

298383
@Retryable

0 commit comments

Comments
 (0)