I have two implementations of one interface - default and dev. I use @ConditionalOnProperty
for default implementation and combination of @Profile
and @ConditionalOnMissingBean
for dev implementation.
@Service
@ConditionalOnProperty(prefix = "keystore", value = "file")
public class DefaultKeyStoreService implements KeyStoreService {
@Service
@Profile("dev")
@ConditionalOnMissingBean(KeyStoreService.class)
public class DevKeyStoreService implements KeyStoreService {
Now, the problem is in test DevKeyStoreServiceTest
for DevKeyStoreService
.
I have configuration like this:
@SpringBootTest(
classes = {DevKeyStoreService.class},
properties = {"keystore.file="}
)
@RunWith(SpringRunner.class)
@ActiveProfiles("dev")
public class DevKeyStoreServiceTest {
@Autowired
private DevKeyStoreService tested;
@Test
public void testPrivateKey() {
} //... etc.
The result is:
Negative matches:
-----------------
DevKeyStoreService:
Did not match:
- @ConditionalOnMissingBean (types: service.crypto.KeyStoreService; SearchStrategy: all) found bean 'devKeyStoreService' (OnBeanCondition)
and the typical org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'service.crypto.DevKeyStoreServiceTest'...
.
How can I configure the test class to be able to run it?
@Bean is a method-level annotation and a direct analog of the XML <bean/> element. The annotation supports most of the attributes offered by <bean/> , such as: init-method , destroy-method , autowiring , lazy-init , dependency-check , depends-on and scope .
The @ConditionalOnMissingBean annotation is a spring conditional annotation for registering beans only when they are not already in the application context.
proxyBeanMethods allows you to invoke one method marked as Bean from another one declared in the same configuration class.
The @ConditionalOnBean annotation let a bean be included based on the presence of specific beans. By default Spring will search entire hierarchy ( SearchStrategy.
The @ConditionalOnMissingBean annotation is used to load a bean only if a given bean is missing: The above bean will get loaded by Spring only if there is no other bean of this type present in the context.
Note that @ConditionalOnMissingBean is not specifying anything at all. There are three such cases in the file. You don't actually need to specify a bean or a type as it should be deduced from the method's return type. In this case that means that it's conditional on there being no IRuntimeConfig bean.
Only if the specified condition is satisfied then only bean will be added to the application context. To declare a condition, you can use any of the @Conditional… annotations. The @ConditionalOnMissingBean annotation lets a bean be included based on the absence of specific beans.
For multiple names you can use @ConditionalOnMissingBean (name = { "springService", "anotherSpringService" }). You can use by search and for this to work you have to use any of the following SearchStrategy.
Ok, I figured it out.
Annotation with value @ConditionalOnMissingBean(KeyStoreService.class)
tries to find only concrete instances, which interface KeyStoreService
is not. This way, it doesn't find anything.
When I use annotation with type instead, it works like a charm: @ConditionalOnMissingBean(type = "KeyStoreService")
.
I think your best bet would to use the name option in @ConditionalOnMissingBean.
The problem you've got now it seems is that the Conditional is find itself and not the missing bean DefaultKeyStoreService.
If you do this
@ConditionalOnMissingBean(name="defaultKeyStoreService")
It will probably work better.
The other option is to specifically have a prod profile to enable the prod bean.
What is interesting is that you can override beans when having a profile if you create those beans with xml.
So if you have in xml
<bean id="x" class="X"/>
And then have
<beans profile="dev">
<bean id="x" class="Y"/>
</beans>
When you enable the dev profile it will replace the x bean in the unprofiled context with the bean x in the dev profile.
The same behaviour does not occur when using annotations however.
Right when profiles came out I logged a bug in this regard, it wasn't taken up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With