Workaround for generic parameter types on inner class constructors

Issue: SPR-16734
This commit is contained in:
Juergen Hoeller
2018-04-17 15:59:08 +02:00
parent 6a727e1ed7
commit c09e10405b
2 changed files with 37 additions and 13 deletions

View File

@@ -337,7 +337,6 @@ public class MethodParameter {
return (isOptional() ? nested() : this);
}
/**
* Set a containing class to resolve the parameter type against.
*/
@@ -390,9 +389,19 @@ public class MethodParameter {
paramType = (method != null ? method.getGenericReturnType() : void.class);
}
else {
paramType = (this.method != null ?
this.method.getGenericParameterTypes()[this.parameterIndex] :
this.constructor.getGenericParameterTypes()[this.parameterIndex]);
Type[] genericParameterTypes = (this.method != null ?
this.method.getGenericParameterTypes() : this.constructor.getGenericParameterTypes());
int index = this.parameterIndex;
if (this.constructor != null && this.constructor.getDeclaringClass().isMemberClass() &&
!Modifier.isStatic(this.constructor.getDeclaringClass().getModifiers()) &&
genericParameterTypes.length == this.constructor.getParameterTypes().length - 1) {
// Bug in javac: type array excludes enclosing instance parameter
// for inner classes with at least one generic constructor parameter,
// so access it with the actual parameter index lowered by 1
index = this.parameterIndex - 1;
}
paramType = (index >= 0 && index < genericParameterTypes.length ?
genericParameterTypes[index] : getParameterType());
}
this.genericParameterType = paramType;
}
@@ -497,12 +506,8 @@ public class MethodParameter {
// for inner classes, so access it with the actual parameter index lowered by 1
index = this.parameterIndex - 1;
}
if (index >= 0 && index < annotationArray.length) {
paramAnns = adaptAnnotationArray(annotationArray[index]);
}
else {
paramAnns = EMPTY_ANNOTATION_ARRAY;
}
paramAnns = (index >= 0 && index < annotationArray.length ?
adaptAnnotationArray(annotationArray[index]) : EMPTY_ANNOTATION_ARRAY);
this.parameterAnnotations = paramAnns;
}
return paramAnns;

View File

@@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import org.junit.Before;
import org.junit.Test;
@@ -96,7 +97,7 @@ public class MethodParameterTests {
@Test // SPR-16652
public void annotatedConstructorParameterInInnerClass() throws Exception {
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Integer.class);
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class);
MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
@@ -107,10 +108,28 @@ public class MethodParameterTests {
assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class));
methodParameter = MethodParameter.forMethodOrConstructor(constructor, 2);
assertEquals(Integer.class, methodParameter.getParameterType());
assertEquals(Callable.class, methodParameter.getParameterType());
assertNull(methodParameter.getParameterAnnotation(Param.class));
}
@Test // SPR-16734
public void genericConstructorParameterInInnerClass() throws Exception {
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class);
MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
assertEquals(getClass(), methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forMethodOrConstructor(constructor, 1);
assertEquals(String.class, methodParameter.getParameterType());
assertEquals(String.class, methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forMethodOrConstructor(constructor, 2);
assertEquals(Callable.class, methodParameter.getParameterType());
assertEquals(ResolvableType.forClassWithGenerics(Callable.class, Integer.class).getType(),
methodParameter.getGenericParameterType());
}
public int method(String p1, long p2) {
return 42;
@@ -126,7 +145,7 @@ public class MethodParameterTests {
@SuppressWarnings("unused")
private class InnerClass {
public InnerClass(@Param String s, Integer i) {
public InnerClass(@Param String s, Callable<Integer> i) {
}
}