|
18 | 18 |
|
19 | 19 | import java.lang.reflect.Method;
|
20 | 20 | import java.util.ArrayList;
|
| 21 | +import java.util.Collections; |
21 | 22 | import java.util.List;
|
| 23 | +import java.util.Map; |
22 | 24 |
|
23 | 25 | import org.junit.Rule;
|
24 | 26 | import org.junit.Test;
|
25 | 27 | import org.junit.rules.ExpectedException;
|
26 | 28 |
|
27 | 29 | import org.springframework.retry.ExhaustedRetryException;
|
| 30 | +import org.springframework.util.CollectionUtils; |
28 | 31 | import org.springframework.util.ReflectionUtils;
|
29 | 32 |
|
30 |
| -import static org.junit.Assert.assertEquals; |
| 33 | +import static org.junit.Assert.*; |
31 | 34 |
|
32 | 35 | /**
|
33 | 36 | * @author Dave Syer
|
@@ -107,6 +110,106 @@ public void parentReturnTypeRecoverMethod() {
|
107 | 110 |
|
108 | 111 | }
|
109 | 112 |
|
| 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 | + |
| 156 | + @Test |
| 157 | + public void genericSpecifiedReturnTypeRecoverMethod() { |
| 158 | + RecoverAnnotationRecoveryHandler<?> fooHandler = new RecoverAnnotationRecoveryHandler<Integer>( |
| 159 | + new GenericInheritanceReturnTypeRecover(), |
| 160 | + ReflectionUtils.findMethod(GenericInheritanceReturnTypeRecover.class, "foo", String.class)); |
| 161 | + @SuppressWarnings("unchecked") |
| 162 | + Map<String, Integer> recoverResponseMapRe = (Map<String, Integer>) fooHandler.recover(new Object[] { "Aldo" }, |
| 163 | + new RuntimeException("Planned")); |
| 164 | + assertEquals(1, recoverResponseMapRe.get("foo").intValue()); |
| 165 | + @SuppressWarnings("unchecked") |
| 166 | + Map<String, Integer> recoverResponseMapIse = (Map<String, Integer>) fooHandler.recover(new Object[] { "Aldo" }, |
| 167 | + new IllegalStateException("Planned")); |
| 168 | + assertEquals(2, recoverResponseMapIse.get("foo").intValue()); |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Even if there are @Recover methods with narrower generic return type, the one with |
| 173 | + * direct match should get called |
| 174 | + */ |
| 175 | + @Test |
| 176 | + public void genericChildReturnTypeRecoverMethod() { |
| 177 | + RecoverAnnotationRecoveryHandler<?> barHandler = new RecoverAnnotationRecoveryHandler<Double>( |
| 178 | + new GenericInheritanceReturnTypeRecover(), |
| 179 | + ReflectionUtils.findMethod(GenericInheritanceReturnTypeRecover.class, "bar", String.class)); |
| 180 | + @SuppressWarnings("unchecked") |
| 181 | + Map<String, Double> recoverResponseMapRe = (Map<String, Double>) barHandler.recover(new Object[] { "Aldo" }, |
| 182 | + new RuntimeException("Planned")); |
| 183 | + assertEquals(0.2, recoverResponseMapRe.get("bar"), 0.0); |
| 184 | + } |
| 185 | + |
| 186 | + @Test |
| 187 | + public void genericMapListIntegerReturnTypeRecoverMethod() { |
| 188 | + RecoverAnnotationRecoveryHandler<?> fooHandler = new RecoverAnnotationRecoveryHandler<Integer>( |
| 189 | + new NestedGenericInheritanceReturnTypeRecover(), |
| 190 | + ReflectionUtils.findMethod(NestedGenericInheritanceReturnTypeRecover.class, "foo", String.class)); |
| 191 | + @SuppressWarnings("unchecked") |
| 192 | + Map<String, Map<String, Map<Integer, String>>> recoverResponseMapRe = (Map<String, Map<String, Map<Integer, String>>>) fooHandler |
| 193 | + .recover(new Object[] { "Aldo" }, new RuntimeException("Planned")); |
| 194 | + assertEquals("fooRecoverReValue", recoverResponseMapRe.get("foo").get("foo").get(0)); |
| 195 | + @SuppressWarnings("unchecked") |
| 196 | + Map<String, Map<String, Map<Integer, String>>> recoverResponseMapIe = (Map<String, Map<String, Map<Integer, String>>>) fooHandler |
| 197 | + .recover(new Object[] { "Aldo" }, new IllegalStateException("Planned")); |
| 198 | + assertEquals("fooRecoverIeValue", recoverResponseMapIe.get("foo").get("foo").get(0)); |
| 199 | + } |
| 200 | + |
| 201 | + @Test |
| 202 | + public void genericMapListDoubleReturnTypeRecoverMethod() { |
| 203 | + RecoverAnnotationRecoveryHandler<?> barHandler = new RecoverAnnotationRecoveryHandler<Double>( |
| 204 | + new NestedGenericInheritanceReturnTypeRecover(), |
| 205 | + ReflectionUtils.findMethod(NestedGenericInheritanceReturnTypeRecover.class, "bar", String.class)); |
| 206 | + @SuppressWarnings("unchecked") |
| 207 | + Map<String, Map<String, Map<Number, String>>> recoverResponseMapRe = (Map<String, Map<String, Map<Number, String>>>) barHandler |
| 208 | + .recover(new Object[] { "Aldo" }, new RuntimeException("Planned")); |
| 209 | + assertEquals("barRecoverNumberValue", recoverResponseMapRe.get("bar").get("bar").get(0.0)); |
| 210 | + |
| 211 | + } |
| 212 | + |
110 | 213 | @Test
|
111 | 214 | public void multipleQualifyingRecoverMethods() {
|
112 | 215 | Method foo = ReflectionUtils.findMethod(MultipleQualifyingRecovers.class, "foo", String.class);
|
@@ -293,6 +396,119 @@ public Number quux(RuntimeException re, String name) {
|
293 | 396 |
|
294 | 397 | }
|
295 | 398 |
|
| 399 | + protected static class GenericReturnTypeRecover { |
| 400 | + |
| 401 | + private static class One { |
| 402 | + |
| 403 | + String name; |
| 404 | + |
| 405 | + public One(String name) { |
| 406 | + this.name = name; |
| 407 | + } |
| 408 | + |
| 409 | + } |
| 410 | + |
| 411 | + @Retryable |
| 412 | + public Map<String, String> foo(String name) { |
| 413 | + return Collections.singletonMap("foo", "fooValue"); |
| 414 | + } |
| 415 | + |
| 416 | + @Retryable |
| 417 | + public Map<String, One> bar(String name) { |
| 418 | + return Collections.singletonMap("bar", new One("barValue")); |
| 419 | + } |
| 420 | + |
| 421 | + @Recover |
| 422 | + public Map<String, String> fooRecoverRe(RuntimeException re, String name) { |
| 423 | + return Collections.singletonMap("foo", "fooRecoverValue1"); |
| 424 | + } |
| 425 | + |
| 426 | + @Recover |
| 427 | + public Map<String, String> fooRecoverIe(IllegalStateException re, String name) { |
| 428 | + return Collections.singletonMap("foo", "fooRecoverValue2"); |
| 429 | + } |
| 430 | + |
| 431 | + @Recover |
| 432 | + public Map<String, One> barRecover(RuntimeException re, String name) { |
| 433 | + return Collections.singletonMap("bar", new One("barRecoverValue")); |
| 434 | + } |
| 435 | + |
| 436 | + } |
| 437 | + |
| 438 | + protected static class GenericInheritanceReturnTypeRecover { |
| 439 | + |
| 440 | + @Retryable |
| 441 | + public Map<String, Integer> foo(String name) { |
| 442 | + return Collections.singletonMap("foo", 0); |
| 443 | + } |
| 444 | + |
| 445 | + @Retryable |
| 446 | + public Map<String, Number> bar(String name) { |
| 447 | + return Collections.singletonMap("bar", (Number) 0.0); |
| 448 | + } |
| 449 | + |
| 450 | + @Recover |
| 451 | + public Map<String, Integer> fooRecoverRe(RuntimeException re, String name) { |
| 452 | + return Collections.singletonMap("foo", 1); |
| 453 | + } |
| 454 | + |
| 455 | + @Recover |
| 456 | + public Map<String, Integer> fooRecoverIe(IllegalStateException re, String name) { |
| 457 | + return Collections.singletonMap("foo", 2); |
| 458 | + } |
| 459 | + |
| 460 | + @Recover |
| 461 | + public Map<String, Double> barRecoverDouble(RuntimeException re, String name) { |
| 462 | + return Collections.singletonMap("bar", 0.1); |
| 463 | + } |
| 464 | + |
| 465 | + @Recover |
| 466 | + public Map<String, Number> barRecoverNumber(RuntimeException re, String name) { |
| 467 | + return Collections.singletonMap("bar", (Number) 0.2); |
| 468 | + } |
| 469 | + |
| 470 | + } |
| 471 | + |
| 472 | + protected static class NestedGenericInheritanceReturnTypeRecover { |
| 473 | + |
| 474 | + @Retryable |
| 475 | + public Map<String, Map<String, Map<Integer, String>>> foo(String name) { |
| 476 | + return Collections.singletonMap("foo", |
| 477 | + Collections.singletonMap("foo", Collections.singletonMap(0, "fooValue"))); |
| 478 | + } |
| 479 | + |
| 480 | + @Retryable |
| 481 | + public Map<String, Map<String, Map<Number, String>>> bar(String name) { |
| 482 | + return Collections.singletonMap("bar", |
| 483 | + Collections.singletonMap("bar", Collections.singletonMap((Number) 0.0, "barValue"))); |
| 484 | + } |
| 485 | + |
| 486 | + @Recover |
| 487 | + public Map<String, Map<String, Map<Integer, String>>> fooRecoverRe(RuntimeException re, String name) { |
| 488 | + return Collections.singletonMap("foo", |
| 489 | + Collections.singletonMap("foo", Collections.singletonMap(0, "fooRecoverReValue"))); |
| 490 | + } |
| 491 | + |
| 492 | + @Recover |
| 493 | + public Map<String, Map<String, Map<Integer, String>>> fooRecoverIe(IllegalStateException re, String name) { |
| 494 | + return Collections.singletonMap("foo", |
| 495 | + Collections.singletonMap("foo", Collections.singletonMap(0, "fooRecoverIeValue"))); |
| 496 | + } |
| 497 | + |
| 498 | + @Recover |
| 499 | + public Map<String, Map<String, Map<Number, String>>> barRecoverNumber(RuntimeException re, String name) { |
| 500 | + return Collections.singletonMap("bar", |
| 501 | + Collections.singletonMap("bar", Collections.singletonMap((Number) 0.0, "barRecoverNumberValue"))); |
| 502 | + } |
| 503 | + |
| 504 | + @Recover |
| 505 | + public Map<String, Map<String, Map<Double, String>>> barRecoverDouble(RuntimeException re, String name) { |
| 506 | + return Collections.singletonMap("bar", |
| 507 | + Collections.singletonMap("bar", Collections.singletonMap(0.0, "barRecoverDoubleValue"))); |
| 508 | + } |
| 509 | + |
| 510 | + } |
| 511 | + |
296 | 512 | protected static class MultipleQualifyingRecoversNoThrowable {
|
297 | 513 |
|
298 | 514 | @Retryable
|
|
0 commit comments