Spring 3.1 Java configuration and inner beans - java

#Bean
public TimedRepository timedRepository(RealRepository repo) {
return new TimedRepository(repo, timer); // Adds some metrics
}
#Bean
public RealRepository realRepository(DataSource ds) {
return new RealRepository(ds); // The real jdbc implementation
}
In the old XML days I would configure the real repository as an anonymous inner bean. Is it possible to do something similar with the new Java configuration approach? Instantiating the real repository inside the timedRepository factory method is not an option because I want Spring to pick up on annotations on RealRepository.
The motivation is to avoid any other beans to get hold of the real repository implementation. I should also mention that both beans implement a Repository interface that'll be used by any beans depending on the repository (they should not have to know about TimedRepository or RealRepository.

I dont think theres an equivalent to inner or local beans when using java based configuration. I'd probably try to create the RealRepository in the TimedRepositories bean method as well by asking for all dependencies in the method signature. But if you really need to have spring to take care of the RealRepository dependencies you need to use the bean factory.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ConfigTest {
#Autowired TimedRepository timedRepo;
#Test
public void testRepository() {
Assert.assertNotNull(timedRepo);
}
#Configuration
static class TimedRepositoryConfiguration {
#Autowired
private AutowireCapableBeanFactory beanFactory;
#Bean
public TimedRepository timedRepository() {
RealRepository realRepository = (RealRepository) beanFactory.createBean(RealRepository.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true);
return new TimedRepository(realRepository);
}
public RealRepository realRepository() {
return new RealRepository();
}
}
static class RealRepository {
}
static class TimedRepository {
private RealRepository realRepo;
public TimedRepository(RealRepository r) {
this.realRepo = r;
}
}
}

You can just instantiate the beans manually:
public class BeanThatDependsOnRealRepository() {
private final Repository repository;
#Inject
public BeanThatDependsOnRealRepository(DataSource dataSource) {
this.repository = new RealRepository(dataSource);
}
}
This is essentially what an anonymous inner bean does in XML. You've just explicitly constructed it and obtained its dependencies from Spring in the constructor of the enclosing class.

Late answer, but this is possible in Spring Core 4+ (and possibly Spring Core 3) with some trickery.
While standard Spring semantics do not support inner bean creation using JavaConfig, the internal functionality around inner beans can be taken advantage of to produce the same results.
Inner beans are produced during property value resolution by the BeanDefinitionValueResolver (see BeanDefinitionValueResolver#resolveValueIfNecessary). The concept of "inner beans" within Spring is primarily enclosed within this value resolver (which is the only producer of inner beans) and within bean factories under the term "contained beans" (from parent class DefaultSingletonBeanRegistry).
We can trick Spring into producing additional inner beans by defining a property as a BeanDefinition, according to the resolution strategy presented in BeanDefinitionValueResolver:
#Configuration
public class MyConfiguration {
private static Logger logger = LoggerFactory.getLogger(MyConfiguration.class);
private RealRepository realRepository;
private Timer timer;
public MyConfiguration(#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") RealRepository realRepository, Timer timer) {
this.realRepository = realRepository;
this.timer = timer;
logger.info("Constructed MyConfiguration {}", this);
}
#Bean
public TimedRepository timedRepository() {
TimedRepository timedRepository = new TimedRepository(this.realRepository, this.timer);
logger.info("Created timed repo: {}", timedRepository);
return timedRepository;
}
public RealRepository realRepository(DataSource dataSource) {
RealRepository realRepository = new RealRepository(dataSource);
logger.info("Created real repo: {}", realRepository);
return realRepository;
}
#Override
public String toString() {
return "MyConfiguration{" +
"realRepository=" + realRepository +
", timer=" + timer +
'}';
}
}
#Component
public class InnerBeanInjectionBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
#Override
public int getOrder() {
// Preempt execution of org.springframework.context.annotation.ConfigurationClassPostProcessor
return 0;
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
String[] beanDefinitionNameList = ((ConfigurableListableBeanFactory) registry).getBeanNamesForType(MyConfiguration.class, true, false);
assert beanDefinitionNameList.length == 1;
BeanDefinition configurationBeanDefinition = registry.getBeanDefinition(beanDefinitionNameList[0]);
BeanDefinition realRepositoryBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MyConfiguration.class)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setFactoryMethod("realRepository")
.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.getBeanDefinition();
configurationBeanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(realRepositoryBeanDefinition);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Do nothing
}
}
The obvious issue with this solution is that it requires manual processing through a BeanDefinitionRegistryPostProcessor, which is a lot of work for a small gain here. What I would suggest instead is the following:
Create a custom annotation (e.g., #InnerBean)
Attach this annotation to methods in #Configuration classes and candidate component classes where desired
Adapt the BeanDefinitionRegistryPostProcessor to scan classes for #InnerBean-annotated static methods (component-classes should be scanned in #postProcessBeanFactory and configuration classes in #postProcessBeanDefinitionRegistry)
Attach the bean definition to the containing bean definition's autowired constructor fields (or setter fields if that is your convention)
The following is an example:
#Target(ElementType.METHOD)
public #interface InnerBean {
}
#Configuration
public class MyConfiguration {
private static Logger logger = LoggerFactory.getLogger(MyConfiguration.class);
private RealRepository realRepository;
private Timer timer;
public MyConfiguration(#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") RealRepository realRepository, Timer timer) {
this.realRepository = realRepository;
this.timer = timer;
logger.info("Constructed MyConfiguration {}", this);
}
#Bean
public TimedRepository timedRepository() {
TimedRepository timedRepository = new TimedRepository(this.realRepository, this.timer);
logger.info("Created timed repo: {}", timedRepository);
return timedRepository;
}
#InnerBean
public static RealRepository realRepository(DataSource dataSource) {
RealRepository realRepository = new RealRepository(dataSource);
logger.info("Created real repo: {}", realRepository);
return realRepository;
}
#Override
public String toString() {
return "MyConfiguration{" +
"realRepository=" + realRepository +
", timer=" + timer +
'}';
}
}
#Component
public class InnerBeanInjectionBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
private static Logger logger = LoggerFactory.getLogger(InnerBeanInjectionBeanFactoryPostProcessor.class);
private Set<BeanDefinition> processedBeanDefinitionSet = new HashSet<>();
#Override
public int getOrder() {
// Preempt execution of org.springframework.context.annotation.ConfigurationClassPostProcessor
return 0;
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry;
String[] configBeanDefinitionNames = beanFactory.getBeanNamesForAnnotation(Configuration.class);
Arrays.stream(configBeanDefinitionNames)
.map(beanFactory::getBeanDefinition)
.filter(this::isCandidateBean)
.peek(this.processedBeanDefinitionSet::add)
.forEach(this::autowireInnerBeans);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Arrays.stream(beanFactory.getBeanDefinitionNames())
.map(beanFactory::getBeanDefinition)
.filter(this::isCandidateBean)
.filter(beanDefinition -> !this.processedBeanDefinitionSet.contains(beanDefinition))
.forEach(this::autowireInnerBeans);
}
private boolean isCandidateBean(BeanDefinition beanDefinition) {
return beanDefinition.getBeanClassName() != null && beanDefinition.getBeanClassName().startsWith("com.example.demo.");
}
private void autowireInnerBeans(BeanDefinition beanDefinition) {
// Get #InnerBean methods
assert beanDefinition instanceof AnnotatedBeanDefinition;
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
Set<MethodMetadata> innerBeanMethods = annotatedBeanDefinition.getMetadata().getAnnotatedMethods(InnerBean.class.getName());
// Attach inner beans as constructor parameters
for (MethodMetadata method : innerBeanMethods) {
String innerBeanName = method.getMethodName();
if (!method.isStatic()) {
logger.error("#InnerBean definition [{}] is non-static. Inner beans must be defined using static factory methods.", innerBeanName);
continue;
}
BeanDefinition innerBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanDefinition.getBeanClassName())
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.setFactoryMethod(innerBeanName)
.getBeanDefinition();
beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(new ConstructorArgumentValues.ValueHolder(innerBeanDefinition, method.getReturnTypeName(), method.getMethodName()));
}
}
}
There will be a few benefits and caveats of doing this. One large benefit is that the bean lifecycle will be managed by the Spring IoC container, meaning that lifecycle callbacks (such as #PostConstruct and #PreDestroy) will be called. The bean can be automatically managed according to the lifecycle of the parent. Caveats include that the beans cannot be injected as factory-method parameters (although with a bit of work you might able to fix this) and that AOP proxying will not be applied to these methods within #Configuration classes (i.e., realRepository() should never be called as it will not reference the singleton inner bean -- instead, the instance field should always be referenced). Further proxying (similar to ConfigurationClassEnhancer.BeanMethodInterceptor) would need to be added in order to apply this.

Related

Spring create generic service multiple times using generic in constructor

I have a service that uses some object as a generic
#Component
#RequiredArgsConstructor
public class SomeGenericService<T extends Base> {
private final T base;
public void someWork(String info) {
base.someAction(info);
}
}
I also have 3 Base implementations marked with #Component(Base1, Base2, Base3)
I want spring itself to create a service with the generic it needs, for the following example
#Component
#RequiredArgsConstructor
public class Runner implements CommandLineRunner {
private final SomeGenericService<Base1> s1;
private final SomeGenericService<Base2> s2;
private final SomeGenericService<Base3> s3;
#Override
public void run(String... args) throws Exception {
String someString = "text";
s1.someWork(someString);
s2.someWork(someString);
s3.someWork(someString);
}
}
But after the launch, the spring does not understand what I want from it.
Parameter 0 of constructor in SomeGenericService required a single bean, but 3 were found:
- base1: defined in file [Base1.class]
- base2: defined in file [Base2.class]
- base3: defined in file [Base3.class]
Is it possible to set this to automatic, without manually configuring it via the #Bean annotation for each service?
You need to define how those beans should be injected. It's a good practice to have some #Configurations for this purpose. Something like:
#Configuration
#Import({
Base1.class,
Base2.class,
Base3.class
})
public class SomeConfig {
#Bean
SomeGenericService<Base1> someGenericService1() {
return new SomeGenericService(new Base1());
}
#Bean
SomeGenericService<Base2> someGenericService2() {
return new SomeGenericService(new Base2());
}
#Bean
SomeGenericService<Base3> someGenericService3() {
return new SomeGenericService(new Base3());
}
}

Spring Boot Custom Bean Loader

I am using JDBI in tandem with Spring Boot. I followed this guide which results in having to create a class: JdbiConfig in which, for every dao wanted in the application context, you must add:
#Bean
public SomeDao someDao(Jdbi jdbi) {
return jdbi.onDemand(SomeDao.class);
}
I was wondering if there is some way within Spring Boot to create a custom processor to create beans and put them in the application context. I have two ideas on how this could work:
Annotate the DAOs with a custom annotation #JdbiDao and write something to pick those up. I have tried just manually injecting these into the application start up, but the problem is they may not load in time to be injected as they are not recognized during the class scan.
Create a class JdbiDao that every repository interface could extend. Then annotate the interfaces with the standard #Repository and create a custom processor to load them by way of Jdbi#onDemand
Those are my two ideas, but I don't know of any way to accomplish that. I am stuck with manually creating a bean? Has this been solved before?
The strategy is to scan your classpath for dao interface, then register them as bean.
We need: BeanDefinitionRegistryPostProcessor to register additional bean definition and a FactoryBean to create the jdbi dao bean instance.
Mark your dao intercface with #JdbiDao
#JdbiDao
public interface SomeDao {
}
Define a FactoryBean to create jdbi dao
public class JdbiDaoBeanFactory implements FactoryBean<Object>, InitializingBean {
private final Jdbi jdbi;
private final Class<?> jdbiDaoClass;
private volatile Object jdbiDaoBean;
public JdbiDaoBeanFactory(Jdbi jdbi, Class<?> jdbiDaoClass) {
this.jdbi = jdbi;
this.jdbiDaoClass = jdbiDaoClass;
}
#Override
public Object getObject() throws Exception {
return jdbiDaoBean;
}
#Override
public Class<?> getObjectType() {
return jdbiDaoClass;
}
#Override
public void afterPropertiesSet() throws Exception {
jdbiDaoBean = jdbi.onDemand(jdbiDaoClass);
}
}
Scan classpath for #JdbiDao annotated interfaces:
public class JdbiBeanFactoryPostProcessor
implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, EnvironmentAware, BeanClassLoaderAware, BeanFactoryAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
private Environment environment;
private ClassLoader classLoader;
#Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
#Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
#Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
#Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// By default, scanner does not accept regular interface without #Lookup method, bypass this
return true;
}
};
scanner.setEnvironment(environment);
scanner.setResourceLoader(resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(JdbiDao.class));
List<String> basePackages = AutoConfigurationPackages.get(beanFactory);
basePackages.stream()
.map(scanner::findCandidateComponents)
.flatMap(Collection::stream)
.forEach(bd -> registerJdbiDaoBeanFactory(registry, bd));
}
private void registerJdbiDaoBeanFactory(BeanDefinitionRegistry registry, BeanDefinition bd) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) bd;
Class<?> jdbiDaoClass;
try {
jdbiDaoClass = beanDefinition.resolveBeanClass(classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
beanDefinition.setBeanClass(JdbiDaoBeanFactory.class);
// Add dependency to your `Jdbi` bean by name
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("jdbi"));
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(jdbiDaoClass));
registry.registerBeanDefinition(jdbiDaoClass.getName(), beanDefinition);
}
}
Import our JdbiBeanFactoryPostProcessor
#SpringBootApplication
#Import(JdbiBeanFactoryPostProcessor.class)
public class Application {
}

In Spring Boot using SimpleThreadScope I get two instances of an object in the same thread

I define an object as with scope "thread".
In some place in the code the instance is obtained with #Autowired and in other place with context getBean(), when comparing the objects, they are different.
Since the object is "thread" scoped I was expecting the same instance of the object to be returned.
Following is the code, first I define a custom scope
#Configuration
public class ThreadScopeRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope("thread", new SimpleThreadScope());
}
}
A test object is defined as:
#Component
#Scope("thread")
public class ThreadScopeObject implements InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadScopeObject.class);
private String field1;
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
#Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("****************** new object - " + this);
}
}
Also a service is defined as:
#Service
public class ThreadScopeService {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadScopeService.class);
#Autowired
private ThreadScopeObject threadScopeObject;
public void showObject() {
LOGGER.info ("ShowObject: " + threadScopeObject);
}
}
And finally a Async method is defined [RunnableService.java]:
#Async
public CompletableFuture<Map> objectInstanceTest() {
ThreadScopeObject o = ApplicationContextHolder.getContext().getBean(ThreadScopeObject.class);
LOGGER.info ("Thread object: " + o);
service.showObject();
return CompletableFuture.completedFuture(new HashMap<>());
}
When running the application I get the following log:
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.ThreadScopeObject - ****************** new object - com.mono.threadSample.ThreadScopeObject#69c8f2bb
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.RunnableService - Thread object: com.mono.threadSample.ThreadScopeObject#69c8f2bb
19:15:27.094 [mcd-async-1] INFO com.mono.threadSample.ThreadScopeService - ShowObject: com.mono.threadSample.ThreadScopeObject#fd0e5b6
I would like to know the reason why an object "thread" scoped is instantiated twice in the same thread.
Code: https://github.com/saavedrah/spring-threadSample
Thank you.
The ThreadScopeService is a singleton by default, so when it is constructed by spring it will get a ThreadScopeObject from the thread that created it and it won't be updated afterwards. There are two ways to solve this:
inject a Provider<ThreadScopeObject> or ObjectFactory<ThreadScopeObject> into ThreadScopeService and call their get methods to retrieve the scoped object when needed.
annotate the ThreadScopeObject with #Scope("thread", proxyMode = ScopedProxyMode.TARGET_CLASS). This will make spring create a proxy around your object, which will delegate all calls to the correctly scoped instance.

#Bean ResourceProcessor with #Autowired

In my Spring Boot 1.5.10 application with Spring Data REST and HATEOAS, I have a ResourceProcessor bean with an #Autowired service, like:
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Autowired
private OrderHandler orderHandler;
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}
When the #Autowired service is added, the resource processor bean is no longer triggered, unfortunately; i.e., when OrderHandler is commented out, the resource processor runs as it should.
Can a ResourceProcessor use #Autowired services; and, if so, what's the right way to construct it?
This part of the #Bean annotation javadoc should interest you :
#Bean Methods in #Configuration Classes
Typically, #Bean methods are declared within #Configuration classes.
In this case, bean methods may reference other #Bean methods in the
same class by calling them directly. This ensures that references
between beans are strongly typed and navigable. Such so-called
'inter-bean references' are guaranteed to respect scoping and AOP
semantics, just like getBean() lookups would.
Example :
#Bean
public FooService fooService() {
return new FooService(fooRepository());
}
#Bean
public FooRepository fooRepository() {
return new JdbcFooRepository(dataSource());
}
It means that you have not to use #Autowired to set the dependency inside the #Bean declaration but reference another method annotated with #Bean.
But do you really need to set the dependency to create your bean ?
No at all. The OrderHandler is used only during the process() invocation.
So you can simply inject OrderHandler at the same level that the method annotated with #Bean and using it in the anonymous class :
#Autowired
private OrderHandler orderHandler; // only change
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}
I guess you can Autowire orderHandler to outer class. In your way it will not work as you create the instance of ResourceProcessor yourself.
#Autowired
private OrderHandler orderHandler;
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}

Injecting Mockito mocks into beans returned through factory methods

I have the following set up:
A sample class that needs to be mocked during testing:
#Component
class MyConfig
{
public String getConfig()
{
return "RealValue";
}
}
An interface that defines a single method and has two implementations:
interface MyInterface
{
String myMethod();
}
class MyImpl1 implements MyInterface
{
private final MyInterface delegate;
private final MyConfig config;
public MyImpl1(final MyInterface delegate, final MyConfig config)
{
this.delegate = delegate;
this.config = config;
}
#Override
public String myMethod()
{
return this.getClass().getSimpleName() + ": " + config.getConfig() + ", " + delegate.myMethod() + ";";
}
}
class MyImpl2 implements MyInterface
{
private final MyConfig config;
public MyImpl2(final MyConfig config)
{
this.config = config;
}
#Override
public String myMethod()
{
return this.getClass().getSimpleName() + ": " + config.getConfig();
}
}
A factory class that prepares a bean of type MyInterface using the MyConfig object that is a spring bean injected into MyFactory:
#Component
class MyFactory
{
#Autowired
private MyConfig config;
// Factory method to create the bean.
#Bean(name = "myInterface")
protected MyInterface myInterface()
{
final MyImpl2 myImpl2 = new MyImpl2(config);
final MyImpl1 myImpl1 = new MyImpl1(myImpl2, config);
return myImpl1;
}
// A simple getter that prepares MyInterface on the fly.
// This is just to demonstrate that getter picks the mock where as
// the factory bean doesn't
public MyInterface getInterface()
{
final MyImpl2 myImpl2 = new MyImpl2(config);
final MyImpl1 myImpl1 = new MyImpl1(myImpl2, config);
return myImpl1;
}
}
A simple test case that checks if the mock version of MyConfig is getting into the bean created using #Bean or not:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:application-context.xml"
})
public class SpringBeanMockExampleTest
{
#Mock
private MyConfig config;
#InjectMocks
#Autowired
protected MyFactory factory;
#Resource
private MyInterface myInterface;
#Before
public void setupMocks()
{
MockitoAnnotations.initMocks(this);
}
/**
* Fails as the return value is "MyImpl1: RealValue, MyImpl2: RealValue;"
*/
#Test
public void testBean()
{
Mockito.when(config.getConfig()).thenReturn("MockValue");
Assert.assertEquals("MyImpl1: MockValue, MyImpl2: MockValue;", myInterface.myMethod());
}
/**
* Assertion passes here.
*/
#Test
public void testGetter()
{
Mockito.when(config.getConfig()).thenReturn("MockValue");
Assert.assertEquals("MyImpl1: MockValue, MyImpl2: MockValue;", factory.getInterface().myMethod());
}
}
I expected the testBean method to pass also, but obviously the mock is not getting injected into the factory bean created in MyFactory.
It seems the mocks are replacing the actual beans after the factory bean creation step is completed. Due to this, the reference in factory beans is not updated with the mock.
How can I fix this so that testBean works as expected?
This won't work.
Your Spring context is initialized first. Afterwards the TestExecutionListeners are executed that handle the dependency injection in your test (e.g. #Autowired).
Then, before each test is run, your #Before method will initialize the Mockito mocks in your test instance of SpringBeanMockExampleTest, effectively overriding the autowired Spring dependencies.
Why? Mockito creates a new instance for all attributes annotated with #InjectMocks, #Mock, #Spy and #Captor.
A possible solution would be to manually set the mocked config in the factory, instead of using #InjectMocks, overriding the Spring config bean.
#Before
public void setupMocks(){
Config config = mock(Config.class);
factory.setConfig(config);
}
Please note that combining mocks with a (Spring) integration tests is bad practice, since mocking should only be done in unit tests.
A better setup would be to setup a separate Config bean in your Spring context using profiles, e.g.:
#Profile("testing")
#Component
public class TestConfig implements Config {
public String getConfig(){
return "testValue";
}
}

Categories

Resources