Re-registering singleton bean on Spring
java, mocking, spring, unit-testing
Solution
The problem here is that registerSingleton method actually does not create a corresponding BeanDefinition, it just registers the instantiated singleton associating it with the name that you have provided and retrieves it via the application Context later - there is no BeanDefinition underlying it though.
So when you call, `applicationContext.removeBeanDefinition(names2Remove);` it fails as there is no bean definition, only the registered fully instantiated bean.
The fix is to not use registerSingleton, but instead to use a form of registerSingleton which uses a BeanDefinition:
Map<String, String> map = new HashMap<String, String>();
map.put("i", "10"); // set all the properties for the mock..
MutablePropertyValues propertyValues = new MutablePropertyValues(map);
beanFactory.registerSingleton(StupidMock.class.getName(), StupidMock.class, propertyValues);
Problem
I have a multi-module project where each module has its own unit tests and provides mocks for classes for that module. I am trying to build an application context where each module could define its own mocks, but later unit tests would be able to override these mocks, for example: ``` public class Test { private static final class StupidMock { } @org.junit.Test public void test() { StaticApplicationContext applicationContext = new StaticApplicationContext(); final ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); StupidMock stupidMock = new StupidMock(); // original mock beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock); StupidMock f1 = applicationContext.getBean(StupidMock.class); if (f1 == null || f1 != stupidMock) { // ensuring mock is retrievable fail("Could not get bean"); } for (String names2Remove : beanFactory.getBeanNamesForType(StupidMock.class)) { applicationContext.removeBeanDefinition(names2Remove); // <-- fails here } StupidMock stupidMock2 = new StupidMock(); // replacement mock beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock2); } } ``` The problem is that this simple snippet fails on attempt to remove the first mock, claiming that there's no such bean (although Spring has just successfully provided me with a name). If I just try to register another mock on top of the first one, Spring complains saying there is already object bound. `DefaultSingletonBeanRegistry` has a `removeSingleton` method which is protected but I have no control over the bean factory owned by `StaticApplicationContext`. I could possibly use reflection and call this protected method anyway but it just feels wrong to do so for a such a simple task. What am I doing wrong? How could I achieve singleton replacement on `StaticApplicationContext`?