Skip to content

Commit ef64945

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 88f792a commit ef64945

File tree

2 files changed

+123
-10
lines changed

2 files changed

+123
-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.
@@ -40,20 +40,22 @@
4040

4141
/**
4242
* Static {@link org.springframework.beans.factory.BeanFactory} implementation
43-
* which allows to register existing singleton instances programmatically.
44-
* Does not have support for prototype beans or aliases.
43+
* which allows one to register existing singleton instances programmatically.
4544
*
46-
* <p>Serves as example for a simple implementation of the
45+
* <p>Does not have support for prototype beans or aliases.
46+
*
47+
* <p>Serves as an example for a simple implementation of the
4748
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
4849
* managing existing bean instances rather than creating new ones based on bean
4950
* definitions, and not implementing any extended SPI interfaces (such as
5051
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).
5152
*
52-
* <p>For a full-fledged factory based on bean definitions, have a look
53-
* at {@link DefaultListableBeanFactory}.
53+
* <p>For a full-fledged factory based on bean definitions, have a look at
54+
* {@link DefaultListableBeanFactory}.
5455
*
5556
* @author Rod Johnson
5657
* @author Juergen Hoeller
58+
* @author Sam Brannen
5759
* @since 06.01.2003
5860
* @see DefaultListableBeanFactory
5961
*/
@@ -78,7 +80,7 @@ public StaticListableBeanFactory() {
7880
* or {@link java.util.Collections#emptyMap()} for a dummy factory which
7981
* enforces operating against an empty set of beans.
8082
* @param beans a {@code Map} for holding this factory's beans, with the
81-
* bean name String as key and the corresponding singleton object as value
83+
* bean name as key and the corresponding singleton object as value
8284
* @since 4.3
8385
*/
8486
public StaticListableBeanFactory(Map<String, Object> beans) {
@@ -89,7 +91,7 @@ public StaticListableBeanFactory(Map<String, Object> beans) {
8991

9092
/**
9193
* Add a new singleton bean.
92-
* Will overwrite any existing instance for the given name.
94+
* <p>Will overwrite any existing instance for the given name.
9395
* @param name the name of the bean
9496
* @param bean the bean instance
9597
*/
@@ -182,7 +184,10 @@ public boolean containsBean(String name) {
182184
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
183185
Object bean = getBean(name);
184186
// In case of FactoryBean, return singleton status of created object.
185-
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
187+
if (bean instanceof FactoryBean) {
188+
return ((FactoryBean<?>) bean).isSingleton();
189+
}
190+
return true;
186191
}
187192

188193
@Override

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

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 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.
@@ -41,6 +41,7 @@
4141
* @author Rod Johnson
4242
* @author Juergen Hoeller
4343
* @author Chris Beams
44+
* @author Sam Brannen
4445
* @since 04.07.2003
4546
*/
4647
public final class BeanFactoryUtilsTests {
@@ -289,4 +290,111 @@ public void testIntDependencies() {
289290
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
290291
}
291292

293+
@Test
294+
public void isSingletonAndIsPrototypeWithStaticFactory() {
295+
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
296+
TestBean bean = new TestBean();
297+
DummyFactory fb1 = new DummyFactory();
298+
DummyFactory fb2 = new DummyFactory();
299+
fb2.setSingleton(false);
300+
TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true);
301+
TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false);
302+
TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true);
303+
TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false);
304+
lbf.addBean("bean", bean);
305+
lbf.addBean("fb1", fb1);
306+
lbf.addBean("fb2", fb2);
307+
lbf.addBean("sfb1", sfb1);
308+
lbf.addBean("sfb2", sfb2);
309+
lbf.addBean("sfb3", sfb3);
310+
lbf.addBean("sfb4", sfb4);
311+
312+
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
313+
assertSame(bean, beans.get("bean"));
314+
assertSame(fb1.getObject(), beans.get("fb1"));
315+
assertTrue(beans.get("fb2") instanceof TestBean);
316+
assertTrue(beans.get("sfb1") instanceof TestBean);
317+
assertTrue(beans.get("sfb2") instanceof TestBean);
318+
assertTrue(beans.get("sfb3") instanceof TestBean);
319+
assertTrue(beans.get("sfb4") instanceof TestBean);
320+
321+
assertEquals(7, lbf.getBeanDefinitionCount());
322+
assertTrue(lbf.getBean("bean") instanceof TestBean);
323+
assertTrue(lbf.getBean("&fb1") instanceof FactoryBean);
324+
assertTrue(lbf.getBean("&fb2") instanceof FactoryBean);
325+
assertTrue(lbf.getBean("&sfb1") instanceof SmartFactoryBean);
326+
assertTrue(lbf.getBean("&sfb2") instanceof SmartFactoryBean);
327+
assertTrue(lbf.getBean("&sfb3") instanceof SmartFactoryBean);
328+
assertTrue(lbf.getBean("&sfb4") instanceof SmartFactoryBean);
329+
330+
assertTrue(lbf.isSingleton("bean"));
331+
assertTrue(lbf.isSingleton("fb1"));
332+
assertTrue(lbf.isSingleton("fb2"));
333+
assertTrue(lbf.isSingleton("sfb1"));
334+
assertTrue(lbf.isSingleton("sfb2"));
335+
assertTrue(lbf.isSingleton("sfb3"));
336+
assertTrue(lbf.isSingleton("sfb4"));
337+
338+
assertTrue(lbf.isSingleton("&fb1"));
339+
assertFalse(lbf.isSingleton("&fb2"));
340+
assertTrue(lbf.isSingleton("&sfb1"));
341+
assertTrue(lbf.isSingleton("&sfb2"));
342+
assertFalse(lbf.isSingleton("&sfb3"));
343+
assertFalse(lbf.isSingleton("&sfb4"));
344+
345+
assertFalse(lbf.isPrototype("bean"));
346+
assertFalse(lbf.isPrototype("fb1"));
347+
assertFalse(lbf.isPrototype("fb2"));
348+
assertFalse(lbf.isPrototype("sfb1"));
349+
assertFalse(lbf.isPrototype("sfb2"));
350+
assertFalse(lbf.isPrototype("sfb3"));
351+
assertFalse(lbf.isPrototype("sfb4"));
352+
353+
assertFalse(lbf.isPrototype("&fb1"));
354+
assertTrue(lbf.isPrototype("&fb2"));
355+
assertTrue(lbf.isPrototype("&sfb1"));
356+
assertFalse(lbf.isPrototype("&sfb2"));
357+
assertTrue(lbf.isPrototype("&sfb3"));
358+
assertTrue(lbf.isPrototype("&sfb4"));
359+
}
360+
361+
362+
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
363+
364+
private final TestBean testBean = new TestBean("enigma", 42);
365+
private final boolean singleton;
366+
private final boolean prototype;
367+
368+
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
369+
this.singleton = singleton;
370+
this.prototype = prototype;
371+
}
372+
373+
@Override
374+
public boolean isSingleton() {
375+
return this.singleton;
376+
}
377+
378+
@Override
379+
public boolean isPrototype() {
380+
return this.prototype;
381+
}
382+
383+
@Override
384+
public boolean isEagerInit() {
385+
return false;
386+
}
387+
388+
@Override
389+
public Class<TestBean> getObjectType() {
390+
return TestBean.class;
391+
}
392+
393+
public TestBean getObject() throws Exception {
394+
// We don't really care if the actual instance is a singleton or prototype
395+
// for the tests that use this factory.
396+
return this.testBean;
397+
}
398+
}
399+
292400
}

0 commit comments

Comments
 (0)