Skip to content

Commit f868486

Browse files
committed
Fix bug in StaticListableBeanFactory.isSingleton()
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 gh-25522
1 parent a67ac82 commit f868486

File tree

2 files changed

+118
-10
lines changed

2 files changed

+118
-10
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,20 +45,22 @@
4545

4646
/**
4747
* Static {@link org.springframework.beans.factory.BeanFactory} implementation
48-
* which allows to register existing singleton instances programmatically.
49-
* Does not have support for prototype beans or aliases.
48+
* which allows one to register existing singleton instances programmatically.
5049
*
51-
* <p>Serves as example for a simple implementation of the
50+
* <p>Does not have support for prototype beans or aliases.
51+
*
52+
* <p>Serves as an example for a simple implementation of the
5253
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
5354
* managing existing bean instances rather than creating new ones based on bean
5455
* definitions, and not implementing any extended SPI interfaces (such as
5556
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).
5657
*
57-
* <p>For a full-fledged factory based on bean definitions, have a look
58-
* at {@link DefaultListableBeanFactory}.
58+
* <p>For a full-fledged factory based on bean definitions, have a look at
59+
* {@link DefaultListableBeanFactory}.
5960
*
6061
* @author Rod Johnson
6162
* @author Juergen Hoeller
63+
* @author Sam Brannen
6264
* @since 06.01.2003
6365
* @see DefaultListableBeanFactory
6466
*/
@@ -83,7 +85,7 @@ public StaticListableBeanFactory() {
8385
* or {@link java.util.Collections#emptyMap()} for a dummy factory which
8486
* enforces operating against an empty set of beans.
8587
* @param beans a {@code Map} for holding this factory's beans, with the
86-
* bean name String as key and the corresponding singleton object as value
88+
* bean name as key and the corresponding singleton object as value
8789
* @since 4.3
8890
*/
8991
public StaticListableBeanFactory(Map<String, Object> beans) {
@@ -94,7 +96,7 @@ public StaticListableBeanFactory(Map<String, Object> beans) {
9496

9597
/**
9698
* Add a new singleton bean.
97-
* Will overwrite any existing instance for the given name.
99+
* <p>Will overwrite any existing instance for the given name.
98100
* @param name the name of the bean
99101
* @param bean the bean instance
100102
*/
@@ -262,7 +264,10 @@ public boolean containsBean(String name) {
262264
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
263265
Object bean = getBean(name);
264266
// In case of FactoryBean, return singleton status of created object.
265-
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
267+
if (bean instanceof FactoryBean) {
268+
return ((FactoryBean<?>) bean).isSingleton();
269+
}
270+
return true;
266271
}
267272

268273
@Override

spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
4343
* @author Rod Johnson
4444
* @author Juergen Hoeller
4545
* @author Chris Beams
46+
* @author Sam Brannen
4647
* @since 04.07.2003
4748
*/
4849
public class BeanFactoryUtilsTests {
@@ -319,4 +320,106 @@ public void testIntDependencies() {
319320
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
320321
}
321322

323+
@Test
324+
public void isSingletonAndIsPrototypeWithStaticFactory() {
325+
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
326+
TestBean bean = new TestBean();
327+
DummyFactory fb1 = new DummyFactory();
328+
DummyFactory fb2 = new DummyFactory();
329+
fb2.setSingleton(false);
330+
TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true);
331+
TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false);
332+
TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true);
333+
TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false);
334+
lbf.addBean("bean", bean);
335+
lbf.addBean("fb1", fb1);
336+
lbf.addBean("fb2", fb2);
337+
lbf.addBean("sfb1", sfb1);
338+
lbf.addBean("sfb2", sfb2);
339+
lbf.addBean("sfb3", sfb3);
340+
lbf.addBean("sfb4", sfb4);
341+
342+
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
343+
assertSame(bean, beans.get("bean"));
344+
assertSame(fb1.getObject(), beans.get("fb1"));
345+
assertTrue(beans.get("fb2") instanceof TestBean);
346+
assertTrue(beans.get("sfb1") instanceof TestBean);
347+
assertTrue(beans.get("sfb2") instanceof TestBean);
348+
assertTrue(beans.get("sfb3") instanceof TestBean);
349+
assertTrue(beans.get("sfb4") instanceof TestBean);
350+
351+
assertEquals(7, lbf.getBeanDefinitionCount());
352+
assertTrue(lbf.getBean("bean") instanceof TestBean);
353+
assertTrue(lbf.getBean("&fb1") instanceof FactoryBean);
354+
assertTrue(lbf.getBean("&fb2") instanceof FactoryBean);
355+
assertTrue(lbf.getBean("&sfb1") instanceof SmartFactoryBean);
356+
assertTrue(lbf.getBean("&sfb2") instanceof SmartFactoryBean);
357+
assertTrue(lbf.getBean("&sfb3") instanceof SmartFactoryBean);
358+
assertTrue(lbf.getBean("&sfb4") instanceof SmartFactoryBean);
359+
360+
assertTrue(lbf.isSingleton("bean"));
361+
assertTrue(lbf.isSingleton("fb1"));
362+
assertTrue(lbf.isSingleton("fb2"));
363+
assertTrue(lbf.isSingleton("sfb1"));
364+
assertTrue(lbf.isSingleton("sfb2"));
365+
assertTrue(lbf.isSingleton("sfb3"));
366+
assertTrue(lbf.isSingleton("sfb4"));
367+
368+
assertTrue(lbf.isSingleton("&fb1"));
369+
assertFalse(lbf.isSingleton("&fb2"));
370+
assertTrue(lbf.isSingleton("&sfb1"));
371+
assertTrue(lbf.isSingleton("&sfb2"));
372+
assertFalse(lbf.isSingleton("&sfb3"));
373+
assertFalse(lbf.isSingleton("&sfb4"));
374+
375+
assertFalse(lbf.isPrototype("bean"));
376+
assertFalse(lbf.isPrototype("fb1"));
377+
assertFalse(lbf.isPrototype("fb2"));
378+
assertFalse(lbf.isPrototype("sfb1"));
379+
assertFalse(lbf.isPrototype("sfb2"));
380+
assertFalse(lbf.isPrototype("sfb3"));
381+
assertFalse(lbf.isPrototype("sfb4"));
382+
383+
assertFalse(lbf.isPrototype("&fb1"));
384+
assertTrue(lbf.isPrototype("&fb2"));
385+
assertTrue(lbf.isPrototype("&sfb1"));
386+
assertFalse(lbf.isPrototype("&sfb2"));
387+
assertTrue(lbf.isPrototype("&sfb3"));
388+
assertTrue(lbf.isPrototype("&sfb4"));
389+
}
390+
391+
392+
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
393+
394+
private final TestBean testBean = new TestBean("enigma", 42);
395+
private final boolean singleton;
396+
private final boolean prototype;
397+
398+
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
399+
this.singleton = singleton;
400+
this.prototype = prototype;
401+
}
402+
403+
@Override
404+
public boolean isSingleton() {
405+
return this.singleton;
406+
}
407+
408+
@Override
409+
public boolean isPrototype() {
410+
return this.prototype;
411+
}
412+
413+
@Override
414+
public Class<TestBean> getObjectType() {
415+
return TestBean.class;
416+
}
417+
418+
public TestBean getObject() throws Exception {
419+
// We don't really care if the actual instance is a singleton or prototype
420+
// for the tests that use this factory.
421+
return this.testBean;
422+
}
423+
}
424+
322425
}

0 commit comments

Comments
 (0)