diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index c3369ef1191..f796bee9506 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -590,6 +590,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac } } } + if (FactoryBean.class.equals(beanClass) && mbd.isSingleton() && + (typesToMatch.length > 1 || (typesToMatch.length == 1 && !typesToMatch[0].equals(FactoryBean.class)))) { + return getSingletonFactoryBeanForTypeCheck(beanName, mbd).getClass(); + } return beanClass; } @@ -642,10 +646,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass); Set> returnTypes = new HashSet>(1); for (Method factoryMethod : candidates) { - if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic - && factoryMethod.getName().equals(mbd.getFactoryMethodName()) - && factoryMethod.getParameterTypes().length >= minNrOfArgs) { - + if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic && + factoryMethod.getName().equals(mbd.getFactoryMethodName()) && + factoryMethod.getParameterTypes().length >= minNrOfArgs) { Class returnType = GenericTypeResolver.resolveReturnTypeForGenericMethod(factoryMethod, args); if (returnType != null) { returnTypes.add(returnType); @@ -684,12 +687,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac // Try to obtain the FactoryBean's object type without instantiating it at all. BeanDefinition fbDef = getBeanDefinition(factoryBeanName); if (fbDef instanceof AbstractBeanDefinition) { - Class fbClass = ((AbstractBeanDefinition)fbDef).getBeanClass(); + Class fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass(); if (ClassUtils.isCglibProxyClass(fbClass)) { // CGLIB subclass methods hide generic parameters. look at the superclass. fbClass = fbClass.getSuperclass(); } - // find the given factory method, taking into account that in the case of + // Find the given factory method, taking into account that in the case of // @Bean methods, there may be parameters present. ReflectionUtils.doWithMethods(fbClass, new ReflectionUtils.MethodCallback() { diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index a1402199254..e5f00787ab9 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -68,6 +68,7 @@ import org.springframework.context.event.ContextStartedEvent; import org.springframework.context.event.ContextStoppedEvent; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.expression.StandardBeanExpressionResolver; +import org.springframework.context.weaving.LoadTimeWeaverAware; import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor; import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; @@ -915,6 +916,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } + // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. + String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, true); + for (String weaverAwareName : weaverAwareNames) { + getBean(weaverAwareName); + } + // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java index 566aa340e35..44b79e6d0e9 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 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. @@ -16,14 +16,17 @@ package org.springframework.context.annotation.configuration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import java.util.Arrays; +import java.util.List; import org.junit.Test; +import test.beans.ITestBean; +import test.beans.TestBean; + +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; @@ -32,6 +35,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.ListFactoryBean; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -46,8 +50,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.support.GenericApplicationContext; -import test.beans.ITestBean; -import test.beans.TestBean; +import static org.junit.Assert.*; /** * Miscellaneous system tests covering {@link Bean} naming, aliases, scoping and error @@ -65,7 +68,7 @@ public class ConfigurationClassProcessingTests { * When complete, the factory is ready to service requests for any {@link Bean} methods * declared by configClasses. */ - private BeanFactory initBeanFactory(Class... configClasses) { + private ListableBeanFactory initBeanFactory(Class... configClasses) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); for (Class configClass : configClasses) { String configBeanName = configClass.getName(); @@ -126,6 +129,42 @@ public class ConfigurationClassProcessingTests { assertEquals(stringBean, "foo"); } + @Test + public void configWithObjectReturnType() { + BeanFactory factory = initBeanFactory(ConfigWithNonSpecificReturnTypes.class); + assertEquals(Object.class, factory.getType("stringBean")); + assertFalse(factory.isTypeMatch("stringBean", String.class)); + String stringBean = factory.getBean("stringBean", String.class); + assertEquals(stringBean, "foo"); + } + + @Test + public void configWithFactoryBeanReturnType() { + ListableBeanFactory factory = initBeanFactory(ConfigWithNonSpecificReturnTypes.class); + assertEquals(List.class, factory.getType("factoryBean")); + assertTrue(factory.isTypeMatch("factoryBean", List.class)); + assertEquals(FactoryBean.class, factory.getType("&factoryBean")); + assertTrue(factory.isTypeMatch("&factoryBean", FactoryBean.class)); + assertTrue(factory.isTypeMatch("&factoryBean", BeanClassLoaderAware.class)); + assertTrue(factory.isTypeMatch("&factoryBean", ListFactoryBean.class)); + assertTrue(factory.getBean("factoryBean") instanceof List); + + String[] beanNames = factory.getBeanNamesForType(FactoryBean.class); + assertEquals(1, beanNames.length); + assertEquals("&factoryBean", beanNames[0]); + + beanNames = factory.getBeanNamesForType(BeanClassLoaderAware.class); + assertEquals(1, beanNames.length); + assertEquals("&factoryBean", beanNames[0]); + + beanNames = factory.getBeanNamesForType(ListFactoryBean.class); + assertEquals(1, beanNames.length); + assertEquals("&factoryBean", beanNames[0]); + + beanNames = factory.getBeanNamesForType(List.class); + assertEquals("factoryBean", beanNames[0]); + } + @Test public void configurationWithPrototypeScopedBeans() { BeanFactory factory = initBeanFactory(ConfigWithPrototypeBean.class); @@ -186,6 +225,19 @@ public class ConfigurationClassProcessingTests { } + @Configuration + static class ConfigWithNonSpecificReturnTypes { + public @Bean Object stringBean() { + return "foo"; + } + public @Bean FactoryBean factoryBean() { + ListFactoryBean fb = new ListFactoryBean(); + fb.setSourceList(Arrays.asList("element1", "element2")); + return fb; + } + } + + @Configuration static class ConfigWithBeanWithAliases {