How to qualify bean with constructor injection - java

I have an interface which is defined in two places like that:
#Configuration
public class AppContext {
#Bean
public SomeInterface usageOne() {
return new SameImpl();
}
#Bean
public SomeInterface usageTwo() {
return new SameImpl(someOtherConfig);
}
#Bean
public Client clientOne(SomeInterface usageOne) {
return new Client(usageOne);
}
#Bean
public OtherClient clientTwo(SomeInterface usageTwo) {
return new OtherClient(usageTwo);
}
}
My client implementation classes do not have any annotations only required constructor. How to qualify the correct interface implementation usage in that case? I don't want to use #Primary as in my case it's semantically incorrect to name one of the usages as primary (they are in some sense equal). I need to pass the same interface with the same implementation class but configured differently for specific use cases of respected clients. I was thinking that naming the parameter by which I inject the implementation to the bean creation method is enough, but Spring complains with: required a single bean, but 2 were found. I don't understand how should I use the #Qualifier annotation.
I'm running with Spring Boot 2.0.4.RELEASE and respected beans and clients created in separate configuration classes so I cannot just call usageTwo() method when creating OtherClient like that: new OtherClient(usageTwo()); as this method is not available in clients configuration class.

As mentioned by #chrylis in the comments, you can simply add the #Qualifier annotation to the #Bean methods like this:
#Bean
public Client clientOne(#Qualifier("usageOne") SomeInterface usageOne) {
return new Client(usageOne);
}
#Bean
public OtherClient clientTwo(#Qualifier("usageTwo") SomeInterface usageTwo) {
return new OtherClient(usageTwo);
}
The value specified as value for the #Qualifier annotation is the respective bean's name. That is either the name of the corresponding #Bean method or the value of the annotation if used like this #Bean("usageThree").

Related

Specify specific bean to be injected from specific configuration class

I am having one problem where bean definition for a single Service are defined in 2 different configuration classes.
#Configuration
public class ConfigurationA{
#Primary
#Bean("beana")
public beanA(){
return Mockito.mock(BeanA.class);
}
#Bean("beanb")
public beanB(){
return new BeanB(beanA());
}
#PostConstruct
public void initialize(){
beanA().dosomething();
}
}
#Configuration
public class ConfigurationB{
#Bean("beana")
public beanA(){
return new BeanA();
}
}
So when intialize() method is called, I am expecting mocked instance of BeanA will be used but its using real instance that is injected via ConfigurationB class.
I have marked "beana" as primary bean so spring should Ideally use this instance but its using the actual real instance defined in different configuration class.
Is there any way we can configure to use the bean definition from ConfigurationA class instead of ConfigurationB?

Multiple beans with the same implementation in Spring boot

I have a situation where I'm using one possible implementation for a particular bean, and it looks like this:
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
This worked great so far, until a new requirement came in, to use an additional interface which for the moment only ImplementationTwo provides implementation, and it wouldn't make sense to use it with ImplementationOne:
#Bean
public SomeOtherInterface someOtherInterface() {
return new ImplementationTwo();
}
I guess this would work, but I'm wondering if this really make sense because in one scenario I could have both beans basically instantiating the same object. Does that make sense ? Is there maybe a better way to achieve the same thing?
I believe, if you have multiple implementations of a single interface, then you should go about specific bean names as below.
Here implementation1 will be the primary bean created and injected where ever we have the Interface1 dependency.
#Primary
#Bean
public Interface1 implementation1() {
return new Implementation2();
}
#Bean
public Interface1 implementation2() {
return new Implementation2();
}
If we need implementation2 injected we need #Resource annotation as below.
#Resource(name="implementation2")
Interface1 implementation2;
You can always define in each place where you're using particular bean a qualifier:
#Bean
public SomeInterface beanName1(){ //impl }
#Bean
public SomeInterface beanName2(){ //impl }
Usage:
#Qualifier("beanName1") SomeInterface interface;
Also 'd need to allow multiple beans in your application.yml/properties file:
spring.main.allow-bean-definition-overriding=true

BeanNotOfRequiredTypeException: Bean named X is expected to be of type X but was actually of type 'com.sun.proxy.$Proxy

I have such classes and Spring context.
How to fix this wrong Java configuration, not xml?
I'd tried some solutions from other posts, but without success.
#Service
#Transactional
public class XCalculationService implements VoidService<X> {
}
public interface VoidService<Input> {
}
#AllArgsConstructor
public class XService {
private XCalculationService calculationService;
}
#Configuration
public class ServiceConfiguration {
#Bean
public OrderService orderService(XCalculationService calculationService) {
return new XService(calculationService);
}
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
}
Error
BeanNotOfRequiredTypeException: Bean named 'calculationService' is expected to be of type 'com.x.XCalculationService' but was actually of type 'com.sun.proxy.$Proxy
Here is 100% fix:
#EnableTransactionManagement(proxyTargetClass = true)
Java proxies are working on interfaces, not concrete classes.
Reasoning with spring documentation: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.
Therefore, when using aspect/proxy based annotations as #Transactional, Spring will attempt to proxify the concrete class and resulting object will be instance of VoidService interface not XCalculationService.
Therefore you can solve it two ways:
use #Arthur solution and turn off Java's interface proxy in favor of CGLib for transaction support
#EnableTransactionManagement(proxyTargetClass = true)
Instead of using XCalculationService type in injectable fields, use only its proxied interface aka VoidService.
I suppose you have got #ComponentScan somewhere activated and it scans your #Service annotated XCalculationService class.
So you should either remove #Service from XCalculationService
or remove
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
from ServiceConfiguration

Is it possible to set a bean name using annotations in Spring Framework?

I have a bean like this:
#Bean
public String myBean(){
return "My bean";
}
I want to autowire it:
#Autowired
#Qualifier("myBean")
public void setMyBean(String myBean){
this.myBean=myBean;
}
I need something like:
#Bean(name="myCustomBean")
Is it possible to use custom names names for beans out of the box? If it isn't possible out of the box then how to create such a bean?
What you are asking is already available in Spring reference
By default, configuration classes use a #Bean method’s name as the
name of the resulting bean. This functionality can be overridden,
however, with the name attribute.
#Configuration
public class AppConfig {
#Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}

How do I express a dependency on a bean defined in an imported configuration in Spring?

I recently started working at a place that uses Java configuration for Spring as opposed to XML and so far I'm loving it.
My question is the following:
If we have a #Configuration annotated class A that imports another #Configuration annotated class B, what is the proper, type-safe way for a bean defined in A to depend on a bean defined in B.
Here's an example I saw in a blog (https://blog.codecentric.de/en/2012/07/spring-dependency-injection-styles-why-i-love-java-based-configuration/):
#Configuration
public class PartnerConfig {
#Bean
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowired
private PartnerConfig partnerConfig;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerConfig.partnerService());
}
}
As a second part to my question, if I was to do the above, would Spring interpret as a bean dependency? That is, when I do
partnerConfig.partnerService()
in the example above, am I getting Spring to fetch me the partnerService bean, or am I just calling a regular java method and creating a new instance of the PartherService (which is NOT what I want, since the bean should be a singleton) ?
EDIT:
It has been suggested to use a #Qualifier. Would this work?
#Configuration
public class PartnerConfig {
#Bean
#MyCustomQualifier
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(#MyCustomQualifier PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
I recommend giving the docs a read: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Refer to the section:
#Bean Methods in #Configuration Classes
This sums it up very well.
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.
Also take a look at: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
Section:
Composing #Configuration classes
Just add the dependency as an argument to the #Bean annotated method and remove the autowiring of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
or simply autowire the PartnerService instead of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowire
private PartnerService partnerService;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerService);
}
}

Categories