diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 73ecb36ed6..66fd13c633 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -182,8 +182,8 @@ class ConstructorResolver { paramNames = pnd.getParameterNames(candidate); } } - argsHolder = createArgumentArray( - beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); + argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, + getUserDeclaredConstructor(candidate), autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { @@ -446,8 +446,7 @@ class ConstructorResolver { LinkedList causes = null; - for (int i = 0; i < candidates.length; i++) { - Method candidate = candidates[i]; + for (Method candidate : candidates) { Class[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { @@ -800,6 +799,21 @@ class ConstructorResolver { return resolvedArgs; } + protected Constructor getUserDeclaredConstructor(Constructor constructor) { + Class declaringClass = constructor.getDeclaringClass(); + Class userClass = ClassUtils.getUserClass(declaringClass); + if (userClass != declaringClass) { + try { + return userClass.getDeclaredConstructor(constructor.getParameterTypes()); + } + catch (NoSuchMethodException ex) { + // No equivalent constructor on user class (superclass)... + // Let's proceed with the given constructor as we usually would. + } + } + return constructor; + } + /** * Template method for resolving the specified argument which is supposed to be autowired. */ diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java index 699e7add10..cedd45bd55 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import javax.inject.Provider; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -103,6 +104,18 @@ public class AutowiredConfigurationTests { assertSame(ctx.getBean(AutowiredConstructorConfig.class).colour, ctx.getBean(Colour.class)); } + @Test + public void testObjectFactoryConstructorWithTypeVariable() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(factory).loadBeanDefinitions( + new ClassPathResource("annotation-config.xml", ObjectFactoryConstructorConfig.class)); + GenericApplicationContext ctx = new GenericApplicationContext(factory); + ctx.registerBeanDefinition("config1", new RootBeanDefinition(ObjectFactoryConstructorConfig.class)); + ctx.registerBeanDefinition("config2", new RootBeanDefinition(ColorConfig.class)); + ctx.refresh(); + assertSame(ctx.getBean(ObjectFactoryConstructorConfig.class).colour, ctx.getBean(Colour.class)); + } + @Test public void testAutowiredAnnotatedConstructorSupported() { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); @@ -257,6 +270,18 @@ public class AutowiredConfigurationTests { } + @Configuration + static class ObjectFactoryConstructorConfig { + + Colour colour; + + // @Autowired + ObjectFactoryConstructorConfig(ObjectFactory colourFactory) { + this.colour = colourFactory.getObject(); + } + } + + @Configuration static class MultipleConstructorConfig {