LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably

Includes a change for factory methods that declare their return type as FactoryBean: When asked for a specific type match (e.g. LoadTimeWeaverAware), we do check early singleton instances as well (reusing the instances that we create for getObjectType checks). This is necessary in order to make @Bean method introspection as capable as XML bean definition introspection, even in case of the @Bean method using a generic FactoryBean declaration for its return type (instead of the FactoryBean impl class).

Issue: SPR-9857
This commit is contained in:
Juergen Hoeller
2012-10-12 16:22:11 +02:00
parent 7c1a2f37f2
commit 679e122326
3 changed files with 75 additions and 12 deletions

View File

@@ -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 <var>configClasses</var>.
*/
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 {