diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 783945fe49..296577b930 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.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. @@ -1328,8 +1328,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp * @param mbd the corresponding bean definition */ protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) { - Class beanClass = predictBeanType(beanName, mbd, FactoryBean.class); - return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)); + Class predictedType = predictBeanType(beanName, mbd, FactoryBean.class); + return (predictedType != null && FactoryBean.class.isAssignableFrom(predictedType)) || + (mbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(mbd.getBeanClass())); } /** diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/Spr8954Tests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/Spr8954Tests.java new file mode 100644 index 0000000000..0cd040b469 --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/Spr8954Tests.java @@ -0,0 +1,96 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Map; + +import org.junit.Test; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; + +/** + * Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor} + * forces the predicted type of a FactoryBean, effectively preventing retrieval of the + * bean from calls to #getBeansOfType(FactoryBean.class). The implementation of + * {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures + * that not only the predicted bean type is considered, but also the original bean + * definition's beanClass. + * + * @author Chris Beams + * @author Oliver Gierke + */ +public class Spr8954Tests { + + @Test + public void repro() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class)); + bf.addBeanPostProcessor(new PredictingBPP()); + + assertThat(bf.getBean("foo"), instanceOf(Foo.class)); + assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class)); + + @SuppressWarnings("rawtypes") + Map fbBeans = bf.getBeansOfType(FactoryBean.class); + assertThat(1, equalTo(fbBeans.size())); + assertThat("&foo", equalTo(fbBeans.keySet().iterator().next())); + + Map aiBeans = bf.getBeansOfType(AnInterface.class); + assertThat(1, equalTo(aiBeans.size())); + assertThat("&foo", equalTo(aiBeans.keySet().iterator().next())); + } + + static class FooFactoryBean implements FactoryBean, AnInterface { + + public Foo getObject() throws Exception { + return new Foo(); + } + + public Class getObjectType() { + return Foo.class; + } + + public boolean isSingleton() { + return true; + } + } + + interface AnInterface { + } + + static class Foo { + } + + interface PredictedType { + + } + + static class PredictingBPP extends InstantiationAwareBeanPostProcessorAdapter { + + @Override + public Class predictBeanType(Class beanClass, String beanName) { + return FactoryBean.class.isAssignableFrom(beanClass) ? + PredictedType.class : + super.predictBeanType(beanClass, beanName); + } + } +}