-
Notifications
You must be signed in to change notification settings - Fork 507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add generic check for function return type #216
Conversation
@deepesh-verma Please sign the Contributor License Agreement! Click here to manually synchronize the status of this Pull Request. See the FAQ for frequently asked questions. |
@deepesh-verma Thank you for signing the Contributor License Agreement! |
4671928
to
85fce38
Compare
RecoverAnnotationRecoveryHandler.this.methods.put(method, | ||
new SimpleMetadata(parameterTypes.length, null)); | ||
if (recover != null && failingMethod.getGenericReturnType() instanceof ParameterizedType) { | ||
if (method.getGenericReturnType().equals(failingMethod.getGenericReturnType())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this fixes the reported issue, unfortunately, I think it needs to be more sophisticated; we need to examine the generic parameter(s) Map<String, Foo>
should match Map<String, Bar>
if Bar
is a subclass of Foo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a method isParameterizedTypeAssignable
to verify the actualTypeArguments
with isAssignableFrom
check. Please review and let me know if this is what we expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@garyrussell I have made the changes as requested. Can you please review?
85fce38
to
92d4191
Compare
Thanks for the contribution; sorry for the delay. After further review; this is incorrect: protected static class GenericInheritanceReturnTypeRecover {
@Retryable
public Map<String, Double> bar(String name) {
return Collections.singletonMap("bar", 0.0);
}
@Recover
public Map<String, Number> quux(RuntimeException re, String name) {
return Collections.singletonMap("bar", 3);
}
} (My original comment was wrong). We can't return a wider type from the recover method; we can, however, return a narrower type, if there is no direct match. This should work... protected static class GenericInheritanceReturnTypeRecover {
@Retryable
public Map<String, Number> bar(String name) {
return Collections.singletonMap("bar", 0.0);
}
@Recover
public Map<String, Double> quux(RuntimeException re, String name) {
return Collections.singletonMap("bar", 3);
}
} ...but I think it would be ok to only allow direct matches because the above would add a lot more complexity. However, we can't stop at the first level of generics; we need to examine nested generic types; this should work, but does not. protected static class MoreComplexGenericInheritanceReturnTypeRecover {
@Retryable
public Map<String, List<Integer>> foo(String name) {
return Collections.singletonMap("foo", Collections.singletonList(0));
}
@Retryable
public Map<String, List<Double>> bar(String name) {
return Collections.singletonMap("bar", Collections.singletonList(0.0));
}
@Recover
public Map<String, List<Integer>> baz(RuntimeException re, String name) {
return Collections.singletonMap("foo", Collections.singletonList(1));
}
@Recover
public Map<String, List<Double>> qux(RuntimeException re, String name) {
return Collections.singletonMap("bar", Collections.singletonList(1.0));
}
} @Test
public void genericMapListIntegerReturnTypeRecoverMethod() {
RecoverAnnotationRecoveryHandler<?> fooHandler = new RecoverAnnotationRecoveryHandler<Integer>(
new MoreComplexGenericInheritanceReturnTypeRecover(),
ReflectionUtils.findMethod(
MoreComplexGenericInheritanceReturnTypeRecover.class, "foo",
String.class));
@SuppressWarnings("unchecked")
Map<String, List<Integer>> recoverResponseMapRe = (Map<String, List<Integer>>) fooHandler
.recover(new Object[] { "Aldo" }, new RuntimeException("Planned"));
assertEquals(1, recoverResponseMapRe.get("foo").get(0).intValue());
}
@Test
public void genericMapListDoubleReturnTypeRecoverMethod() {
RecoverAnnotationRecoveryHandler<?> barHandler = new RecoverAnnotationRecoveryHandler<Double>(
new MoreComplexGenericInheritanceReturnTypeRecover(),
ReflectionUtils.findMethod(
MoreComplexGenericInheritanceReturnTypeRecover.class, "bar",
String.class));
@SuppressWarnings("unchecked")
Map<String, List<Double>> recoverResponseMapRe = (Map<String, List<Double>>) barHandler
.recover(new Object[] { "Aldo" }, new RuntimeException("Planned"));
assertEquals(1.0, recoverResponseMapRe.get("bar").get(0).doubleValue(), 0.0);
} The second test matches |
Thanks for the feedback and the test cases; It helps a lot to clearly understand what is expected here;
|
d95c9b3
to
e3a6a1d
Compare
Fixes: [spring-projects#215](spring-projects#215) Signed-off-by: deepesh-verma <deepeshvrm1@gmail.com>
Changes -
@garyrussell, Please review. |
It's best to add a new commit rather than force-pushing so we can more easily see what changed. |
Sorry for that. I will make sure to add new commits going forward. |
Fixes: #215
Signed-off-by: deepesh-verma deepeshvrm1@gmail.com