diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 67ec455140..8002dcfc8f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 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. @@ -588,6 +588,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; } @@ -672,12 +676,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/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 297f0a0ca3..a26a9b9d8c 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/org.springframework.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; @@ -908,6 +909,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/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java index 566aa340e3..44b79e6d0e 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java +++ b/org.springframework.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 {