Browse Source

Workaround for generic parameter types on inner class constructors

Issue: SPR-16734
pull/1798/head
Juergen Hoeller 8 years ago
parent
commit
4cd43dc793
  1. 53
      spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
  2. 22
      spring-core/src/main/java/org/springframework/core/MethodParameter.java
  3. 25
      spring-core/src/test/java/org/springframework/core/MethodParameterTests.java

53
spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java

@ -37,6 +37,7 @@ import org.springframework.beans.factory.BeanCreationException; @@ -37,6 +37,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Lookup;
@ -351,7 +352,7 @@ public class ConfigurationClassPostProcessorTests { @@ -351,7 +352,7 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Test
@Test // SPR-15384
public void nestedConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedNestedClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@ -363,6 +364,19 @@ public class ConfigurationClassPostProcessorTests { @@ -363,6 +364,19 @@ public class ConfigurationClassPostProcessorTests {
assertSame(foo, bar.foo);
}
@Test // SPR-16734
public void innerConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedInnerClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
Foo foo = beanFactory.getBean(Foo.class);
assertTrue(foo instanceof ExtendedFoo);
Bar bar = beanFactory.getBean(Bar.class);
assertSame(foo, bar.foo);
}
@Test
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
@ -890,6 +904,43 @@ public class ConfigurationClassPostProcessorTests { @@ -890,6 +904,43 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Configuration
static class ConfigWithOrderedInnerClasses {
@Configuration
@Order(1)
class SingletonBeanConfig {
public SingletonBeanConfig(ConfigWithOrderedInnerClasses other) {
}
public @Bean Foo foo() {
return new Foo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
@Configuration
@Order(2)
class OverridingSingletonBeanConfig {
public OverridingSingletonBeanConfig(ObjectProvider<SingletonBeanConfig> other) {
other.getObject();
}
public @Bean ExtendedFoo foo() {
return new ExtendedFoo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
}
static class Foo {
}

22
spring-core/src/main/java/org/springframework/core/MethodParameter.java

@ -419,7 +419,18 @@ public class MethodParameter { @@ -419,7 +419,18 @@ public class MethodParameter {
paramType = (method != null ? method.getGenericReturnType() : void.class);
}
else {
paramType = this.executable.getGenericParameterTypes()[this.parameterIndex];
Type[] genericParameterTypes = this.executable.getGenericParameterTypes();
int index = this.parameterIndex;
if (this.executable instanceof Constructor &&
ClassUtils.isInnerClass(this.executable.getDeclaringClass()) &&
genericParameterTypes.length == this.executable.getParameterCount() - 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;
}
@ -525,12 +536,8 @@ public class MethodParameter { @@ -525,12 +536,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;
@ -770,7 +777,6 @@ public class MethodParameter { @@ -770,7 +777,6 @@ public class MethodParameter {
}
return false;
}
}
}

25
spring-core/src/test/java/org/springframework/core/MethodParameterTests.java

@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy; @@ -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;
@ -114,7 +115,7 @@ public class MethodParameterTests { @@ -114,7 +115,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.forExecutable(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
@ -125,10 +126,28 @@ public class MethodParameterTests { @@ -125,10 +126,28 @@ public class MethodParameterTests {
assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class));
methodParameter = MethodParameter.forExecutable(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.forExecutable(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
assertEquals(getClass(), methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forExecutable(constructor, 1);
assertEquals(String.class, methodParameter.getParameterType());
assertEquals(String.class, methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forExecutable(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;
@ -144,7 +163,7 @@ public class MethodParameterTests { @@ -144,7 +163,7 @@ public class MethodParameterTests {
@SuppressWarnings("unused")
private class InnerClass {
public InnerClass(@Param String s, Integer i) {
public InnerClass(@Param String s, Callable<Integer> i) {
}
}

Loading…
Cancel
Save