Skip to content

Commit

Permalink
Fix bug in StaticListableBeanFactory.isSingleton()
Browse files Browse the repository at this point in the history
Prior to this commit, StaticListableBeanFactory.isSingleton() returned
false for singleton beans unless they were created by a FactoryBean.

StaticListableBeanFactory.isSingleton() now properly returns true for
all beans not created by a FactoryBean.

Closes spring-projectsgh-25522
  • Loading branch information
sbrannen authored and zx20110729 committed Feb 18, 2022
1 parent 3ca293c commit acebecc
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 10 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -45,20 +45,22 @@

/**
* Static {@link org.springframework.beans.factory.BeanFactory} implementation
* which allows to register existing singleton instances programmatically.
* Does not have support for prototype beans or aliases.
* which allows one to register existing singleton instances programmatically.
*
* <p>Serves as example for a simple implementation of the
* <p>Does not have support for prototype beans or aliases.
*
* <p>Serves as an example for a simple implementation of the
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
* managing existing bean instances rather than creating new ones based on bean
* definitions, and not implementing any extended SPI interfaces (such as
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).
*
* <p>For a full-fledged factory based on bean definitions, have a look
* at {@link DefaultListableBeanFactory}.
* <p>For a full-fledged factory based on bean definitions, have a look at
* {@link DefaultListableBeanFactory}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 06.01.2003
* @see DefaultListableBeanFactory
*/
Expand All @@ -83,7 +85,7 @@ public StaticListableBeanFactory() {
* or {@link java.util.Collections#emptyMap()} for a dummy factory which
* enforces operating against an empty set of beans.
* @param beans a {@code Map} for holding this factory's beans, with the
* bean name String as key and the corresponding singleton object as value
* bean name as key and the corresponding singleton object as value
* @since 4.3
*/
public StaticListableBeanFactory(Map<String, Object> beans) {
Expand All @@ -94,7 +96,7 @@ public StaticListableBeanFactory(Map<String, Object> beans) {

/**
* Add a new singleton bean.
* Will overwrite any existing instance for the given name.
* <p>Will overwrite any existing instance for the given name.
* @param name the name of the bean
* @param bean the bean instance
*/
Expand Down Expand Up @@ -262,7 +264,10 @@ public boolean containsBean(String name) {
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return singleton status of created object.
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
if (bean instanceof FactoryBean) {
return ((FactoryBean<?>) bean).isSingleton();
}
return true;
}

@Override
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -43,6 +43,7 @@
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @since 04.07.2003
*/
public class BeanFactoryUtilsTests {
Expand Down Expand Up @@ -319,4 +320,106 @@ public void testIntDependencies() {
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
}

@Test
public void isSingletonAndIsPrototypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean bean = new TestBean();
DummyFactory fb1 = new DummyFactory();
DummyFactory fb2 = new DummyFactory();
fb2.setSingleton(false);
TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true);
TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false);
TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true);
TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false);
lbf.addBean("bean", bean);
lbf.addBean("fb1", fb1);
lbf.addBean("fb2", fb2);
lbf.addBean("sfb1", sfb1);
lbf.addBean("sfb2", sfb2);
lbf.addBean("sfb3", sfb3);
lbf.addBean("sfb4", sfb4);

Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
assertSame(bean, beans.get("bean"));
assertSame(fb1.getObject(), beans.get("fb1"));
assertTrue(beans.get("fb2") instanceof TestBean);
assertTrue(beans.get("sfb1") instanceof TestBean);
assertTrue(beans.get("sfb2") instanceof TestBean);
assertTrue(beans.get("sfb3") instanceof TestBean);
assertTrue(beans.get("sfb4") instanceof TestBean);

assertEquals(7, lbf.getBeanDefinitionCount());
assertTrue(lbf.getBean("bean") instanceof TestBean);
assertTrue(lbf.getBean("&fb1") instanceof FactoryBean);
assertTrue(lbf.getBean("&fb2") instanceof FactoryBean);
assertTrue(lbf.getBean("&sfb1") instanceof SmartFactoryBean);
assertTrue(lbf.getBean("&sfb2") instanceof SmartFactoryBean);
assertTrue(lbf.getBean("&sfb3") instanceof SmartFactoryBean);
assertTrue(lbf.getBean("&sfb4") instanceof SmartFactoryBean);

assertTrue(lbf.isSingleton("bean"));
assertTrue(lbf.isSingleton("fb1"));
assertTrue(lbf.isSingleton("fb2"));
assertTrue(lbf.isSingleton("sfb1"));
assertTrue(lbf.isSingleton("sfb2"));
assertTrue(lbf.isSingleton("sfb3"));
assertTrue(lbf.isSingleton("sfb4"));

assertTrue(lbf.isSingleton("&fb1"));
assertFalse(lbf.isSingleton("&fb2"));
assertTrue(lbf.isSingleton("&sfb1"));
assertTrue(lbf.isSingleton("&sfb2"));
assertFalse(lbf.isSingleton("&sfb3"));
assertFalse(lbf.isSingleton("&sfb4"));

assertFalse(lbf.isPrototype("bean"));
assertFalse(lbf.isPrototype("fb1"));
assertFalse(lbf.isPrototype("fb2"));
assertFalse(lbf.isPrototype("sfb1"));
assertFalse(lbf.isPrototype("sfb2"));
assertFalse(lbf.isPrototype("sfb3"));
assertFalse(lbf.isPrototype("sfb4"));

assertFalse(lbf.isPrototype("&fb1"));
assertTrue(lbf.isPrototype("&fb2"));
assertTrue(lbf.isPrototype("&sfb1"));
assertFalse(lbf.isPrototype("&sfb2"));
assertTrue(lbf.isPrototype("&sfb3"));
assertTrue(lbf.isPrototype("&sfb4"));
}


static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {

private final TestBean testBean = new TestBean("enigma", 42);
private final boolean singleton;
private final boolean prototype;

TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
this.singleton = singleton;
this.prototype = prototype;
}

@Override
public boolean isSingleton() {
return this.singleton;
}

@Override
public boolean isPrototype() {
return this.prototype;
}

@Override
public Class<TestBean> getObjectType() {
return TestBean.class;
}

public TestBean getObject() throws Exception {
// We don't really care if the actual instance is a singleton or prototype
// for the tests that use this factory.
return this.testBean;
}
}

}

0 comments on commit acebecc

Please sign in to comment.