Autowire a specific bean given a profile - java

I have 2 classes implementing InterfaceA
#Service("classA")
class ClassA implements InterfaceA
#Service("classB")
class ClassB implements InterfaceA
I need to load both beans. In class C and D, though, I need to specify the bean that I need
class ClassC {
#Autowired
#Qualifier("classA")
private InterfaceA interf;
}
class ClassD {
#Autowired
#Qualifier("classA")
private InterfaceA interf;
}
However, I have 2 profiles, profile1 and profile2. If i use -Dspring.profiles.active=profile1, I should be using qualifier "classA" for classC and classD. If i use -Dspring.profiles.active=profile2, I should use "classB" as qualifier. Also, another ClassE should always use classB regardless of the profile. Can you please advise how should I do it?

So this is how I did it. I created a configuration class
#Configuration
public class ConfigClass {
#Autowired
private ClassB classB;
#Profile("profile1")
#Qualifier("myclass")
#Bean
private InterfaceA classAtProfile1() {return new ClassA();}
#Profile("profile2")
#Qualifier("myclass")
#Bean
private InterfaceA classAtProfile2() {return classB;}
}
class ClassA implements InterfaceA
#Service("classB")
class ClassB implements InterfaceA
This way, I can autowire InterfaceA based on profile
#Autowired
#Qualifier("myclass")
private InterfaceA myclass;
While ClassE can still refer to classB
#Component
public class ClassE {
#Autowired
ClassB classB;
...
}

Define 2 configuration java files:
class ClassA implements InterfaceA
class ClassB implements InterfaceA
Sample config file 1:
Profile1Config.java
#Configuration
#Profile("profile1")
public class Profile1Config {
#Bean
public InterfaceA interfaceA() {
return new ClassA();
}
}
Sample config file 2:
Profile1Config.java
#Configuration
#Profile("profile2")
public class Profile2Config {
#Bean
public InterfaceA interfaceA() {
return new ClassB();
}
}
And wherever you want to use this:
class ClassC {
#Autowired
private InterfaceA interf;
}
class ClassD {
#Autowired
private InterfaceA interf;
}
Key point to note:
1. #Qualifier was not required.
2. #Profile is mentioned at the Java Configuration class.
3. #Service was removed from classA and classB rather defined in Config* classes now.

Related

Spring #Qualifer not working with Bean implementing multiple interface

I have a bean which implements two interfaces. Below is my code-
#Qualifier("A")
interface InterfaceA {
method a()
}
#Qualifier("B")
interface InterfaceB {
method b()
}
public class ClassC implements InterfaceA, InterfaceB {
method a(){}
method b(){}
}
When I inject my bean in some other class, say
public class MyClass {
#Autowired
#Qualifier("A")
private InterfaceA a;
#Autowired
#Qualifier("B")
private InterfaceA b;
}
I get below error whether I use Qualifier or not
UnsatisfiedDependencyException: Error creating bean with name a... nosuchbeandefinitionexception
By using the #Qualifier annotation, we can eliminate the issue of which bean needs to be injected. So it is used with #Component annotation above classes, not interfaces.
In your case, you have just one class ClassC that implements two interfaces InterfaceA and InterfaceB.
So to resolve the issue, you need to add #Component to ClassC:
#Component
public class ClassC implements InterfaceA, InterfaceB {
method a(){}
method b(){}
}
And finally, you should remove all #Qualifier annotations, from MyClass and InterfaceA and InterfaceB.
Take look at this to know more about how to use #Qualifier.
#Component is missing on your class C. Also make sure your component scan covers the package in which class C is present.

How to #Autowired a concrete implementation of a service?

I have the following situation:
public interface ServiceAura extends Serializable { }
#Service
public class ServiceA implements ServiceAura {
....
}
#Service
public class ServiceB implements ServiceAura {
....
}
Now from the controller I need to call both of them by separate:
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
private ServiceAura srvA;
#Autowired
private ServiceAura srvB;
}
I have read about #Qualified, is this the only way? How can I archive this?
You're right. You can use #Qualifier("ServiceA") to specify which implementation you want to autowire.
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
#Qualifier("ServiceA")
private ServiceAura srvA;
#Autowired
#Qualifier("ServiceB")
private ServiceAura srvB;
}
On the service itself, you can use the annotation #Primary to specify which one is the default implementation that you want.
Alternatively, you can use the application context to retrieve a specific bean. You'll need to autowire the ApplicationContext class and then retrieve it with ServiceAura srvA = context.getBean(ServiceA.class);
There are two ways to do this.
The first way is using #Qualifier annotation as you've stated.
#Path("")
#Controller
public class ServiciosAuraPortalRESTfulService {
#Autowired
#Qualifier("serviceA")
private ServiceAura srvA;
#Autowired
#Qualifier("serviceB")
private ServiceAura srvB;
}
Your services should be defined like this:
#Service
#Qualifier("serviceA")
public class ServiceA implements ServiceAura {
....
}
#Service
#Qualifier("serviceB")
public class ServiceB implements ServiceAura {
....
}
Another way is to create interfaces that extend interface ServiceAura
interface ServiceAInterface extends ServiceAura {
}
class ServiceA implements ServiceAInterface {}
.... // the same for service B
And then in code:
public class ServiciosAuraPortalRESTfulService {
#Autowired
ServiceAInterface serviceA;
}

Create instance of call with autowire

I have to create a instance of a class, that have autowired elements, for test.
public class MyClass extends SomeOtherClass {
#Autowired
public MyClass(OtherClass1 one, OtherClass2 two){
super(one, two)
}
}
How can i in code create instance of this class, with the arguments wired in though spring?
Your test can be made Spring-aware if you use the SpringJUnit4ClassRunner to read in your Spring Context to be used in the test. For instance:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"the-config.xml"})
public final class MyClassTests {
#Autowired
private MyClass testee;
#Test
public void testSomething() {
assertThat(testee).doesSomethingExpected();
}
}
Note that you should reuse as much of your production config as possible and not create a parallel Spring Context config that mirrors it.
Instead of passing the other elements in as constructor arguments, you Autowire them as properties. Spring will then inject the objects.
public class MyClass extends SomeOtherClass {
#Autowired
private OtherClass1 one;
#Autowired
private OtherClass2 two
public MyClass(){
super(one, two)
}
}
Edit: Based on http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/, adding #Autowired to the constructor is also valid.
If you want to Autowire MyClass, you must annotate it with #Component or a similar annotation such as #Service.
#Component
public class MyClass extends SomeOtherClass
Then, you can use it in other classes
public class ClassThatUsesMyClass {
#Autowire
private MyClass myClass;
}

Spring autowiring issue in spring batch

I seem to be having an issue with the way I have implemented autowiring in my Spring Batch application.For example if I use:
public class A{
#Autowired
BeanList beanList;
}
this works fine for Class A.In the sense that,beanList returns the values that it should.But if from a method from class A I am calling a method from a different class and then have the same
#Autowired
BeanList beanList
,beanList return a null.But autowiring seems to work fine across steps.I have
I'm not sure if I understood your question correctly. I assume, you have something like this:
public class A{
B aB;
#Autowired
BeanList beanList;
public void callToB() { aB.aMethod(); }
}
public class B {
#Autowired
BeanList beanList;
public void aMethod() {Assert.notNull(beanList);}
}
If this is correct, then the problem is likely that you didn't instantiate class B as a "spring bean".
The most simply way to do this would be to mark class B with #Component and to autowire it into class A.
public class A {
#Autowired
B aB;
or to instantiate it with an #Bean directly in class A
#Component
public class A {
#Autowired
BeanList beanList;
#Bean
B myBean() {return new B();}
public void callToB() { myBean().aMethod(); }
Does this describe and solve your problem?

Beans creation faild in spring

I have an interface like this
public interface InterfaceA {
public String methodA();
}
and I have implemented it like this
public class ClassA implements InterfaceA {
#Override
public String methodA(){
return "HELLO";
}
}
I'm trying to reference a bean of this class in another class
public class ClassB {
#Autowired
private InterfaceA mybean;
String str = mybean.methodA();
}
I have the following bean configuration
<bean id="mybean" class="ClassA"></bean>
Most interesting point is if I remove all the declaration and implementation of the methodA in InterfaceA and ClassA and then try to just this
public class ClassB {
#Autowired
private InterfaceA mybean;
}
no error is shown.
In the other case the following error is shown when I try to run this application: "No qualifying bean of type [ClassA] found for dependency"
It is because of the livecyle of a bean and a java class!
in your ClassB you have two variables. mybean will been populated by Spring after the object instance ins created (by spring). But String str = mybean.methodA(); will be assinged as soon as the object instance is created. And at this point the variable mybean is still null, and therfor the instance creation will fail!
Solution: use #PostConstruct, spring init-method, or implement InitializingBean -- see this answer for an overview
public class ClassB {
#Autowired
private InterfaceA mybean;
private String str;
void afterPropertiesSet() {
String str = mybean.methodA();
}
}

Categories

Resources