Autowiring of beans in spring boot with #Qualifier annotation - spring

I am learning autowiring in Spring Boot using #Primary and #Qualifier annotations. I am able to understand that #Primary wires the annotated class as a dependency and in case more than one satisfying classes are found #Qualifier can come to help.
#Component
public class VehicleBean {
#Autowired
#Qualifier("car")
Vehicle car;
public void check() {
car.details();
}
public Vehicle getCar() {
return car;
}
public void setCar(Vehicle car) {
this.car = car;
}
}
Bike
#Component
//#Primary
#Qualifier("car")
public class Bike implements Vehicle {
#Override
public void details() {
System.out.println("Bike is driving");
}
}
Car
#Component
//#Primary
#Qualifier("bike")
public class Car implements Vehicle {
#Override
public void details() {
System.out.println("Car is driving");
}
}
When I add #Qualifier("car") on my autowired dependency named as "bike" and have #Qualifier("car") on Car and #Qualifier("bike") on Bike, it picks up Car. However, when I interchange the #Qualifier on Bike and Car(e.g - #Qualifier("bike") on Car and vice versa) it picks up the bike. Also when I change the #Qualifier to "bike on my autowired dependency named as "car" and have #Qualifier("car") on Bike and vice verse, it is picking Car. I was expecting Bike to be picked. What am I missing?

The use of qualifier annotation here is incorrect, the qualifier annotation is used on a field, a parameter or a method to pick the write candidate bean while authowiring,
This annotation may be used on a field or parameter as a qualifier for
candidate beans when autowiring. (JAVA DOC)
In simple word, you define the beans by name and you tell spring what name to pick by adding #Qualifier, in your example you have to add the bean name in #Component.
#Component("bike")
public class Bike implements Vehicle {
#Override
public void details() {
System.out.println("Bike is driving");
}
}
#Component("car")
public class Car implements Vehicle {
#Override
public void details() {
System.out.println("Car is driving");
}
}
Coming to your question, why it picks Car? , because the AnnotationBeanNameGenerator generate a default name if no one specified and the built name is based on the short name of the class (with the first letter lower-cased):
If the annotation's value doesn't indicate a bean name, an appropriate
name will be built based on the short name of the class (with the
first letter lower-cased). For example:
com.xyz.FooServiceImpl -> fooServiceImpl (JAVA DOC)

#Qualifier annotation won't work here #Component #Qualifier("car"). It can be used on a field, a parameter or a method for autowiring.
You need to pass the name with #Component annotation only, like #Component("car")

Related

How to declare multiple object with same class but using different properties in spring boot

I want declare multiple object using same class but different properties in Spring boot annotation
application.properties
test1.name=Ken
test2.name=Anthony
the code example
#Component
public class People {
private String name;
public String getName() {
return this.name;
}
}
#SpringBootApplication
public class Application {
#AutoWired
public People man1;
#AutoWired
public People man2;
System.out.println(man1.getName());
System.out.println(man2.getName());
}
I try to add #ConfigurationProperties(prefix="test1") before declare man1
but it returned
The annotation #ConfigurationProperties is disallowed for this location
#ConfigurationProperties is only allow to be placed on the #Bean method in the #Configuration class or at the class level. For the former case , it will map the properties from the application.properties to the bean instance , which means you have to :
#SpringBootApplication
public class Application {
#Bean
#ConfigurationProperties(prefix="test1")
public People man1() {
return new People();
}
#Bean
#ConfigurationProperties(prefix="test2")
public People man2() {
return new People();
}
}
And since both man1 and man2 are the same type , you have to further use #Qualifier to tell Spring which instance you actually want to inject by specifying its bean name. The bean name can be configured by #Bean("someBeanName"). If #Bean is used without configuring the bean name, the method name will be used as the bean name. (i.e. man1 and man2)
#Autowired
#Qualifier("man1")
public People man1;
#Autowired
#Qualifier("man2")
public People man2;

#AutoWired without #Qualifier

If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable? I saw in the documentation, "As a fallback Spring uses the bean name as a default qualifier value".
#Component
class A{
}
#Component
class B extends A{
}
class C{
#AutoWired
A a;
//Will a be of type class A, even without #Qualifier...?
}
If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable?
#Autowire in the first place cares about type, later about the name. You will get exception saying that there are multiple candidates for injection while only 1 is expected.
#Resource on the other hand, cares about name first, type later.
In this case, B will get injected because there is an A and a B for Spring to choose from and only one of them matches what the #Autowired field is asking for (Class B, because A is not assignable to B).
However, if you had two B's, you would have to qualify it or mark one of them as the primary.
For example, given this:
#Configuration
public class MyConfig {
#Bean
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
Well, now you have two instances of B, with different names. You can fix this one of two ways:
Qualify your Autowire
Note that I'm using field injection here, you really should use constructor, I'm doing it to save space.
#Component
public class SomeComponent {
#Autowired
#Qualifier("example1")
private B b;
}
Or
Mark A Bean as Primary
Redefine the beans, marking one as #Primary
#Configuration
public class MyConfig {
#Bean
#Primary // <-------- NEW!
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
And then inject without needing to name it:
#Component
public class SomeComponent {
#Autowired // (Will pick Primary)
private B b;
}

Spring bean with same method name but different qualifier fail to load

I have two Spring Configuration classes defined as follows
#Configuration
public class ClsA {
#Bean
#Qualifier("ClasA")
public String getSomething(){
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean
#Qualifier("ClsB")
public String getSomething(){
return "somethingB";
}
}
Both have the same method name. Even though qualifiers are different, the application doesn't load as it only injects one and wherever the other one is injected, if fails with noBeanDefinition exception let's say for ClsB bean qualifier.
When I keep the method name different and everything loads hunky dory.
Is this behavior normal ? Why doesn't spring load these beans just fine as they have different qualifiers ?
The #Qualifier annotation is supposed to be used at injection points to resolve ambiguity as to which bean to inject. But in the example, you use it at bean declaration site. At declaration site, you can give a name to each bean by specifying it in #Bean annotation. So if you leave your methods with the same name, then a valid example can be as follows:
#Configuration
public class ClsA {
#Bean("ClasA")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("ClasB")
public String getSomething() {
return "somethingB";
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ClsB.class, ClsA.class})
public class ClsTest {
#Autowired
#Qualifier("ClasA") //this is the place where #Qualifier can be used
String smthA;
#Autowired
#Qualifier("ClasB")
String smthB;
#Test
public void test() {
System.out.println(smthA);
System.out.println(smthB);
}
}
Output:
somethingA
somethingB
1. Customize Bean Naming
Each bean name must be unique.
1.3.1. Naming Beans
1.12.3. Using the #Bean Annotation > Customizing Bean Naming
#Configuration
public class ClsA {
#Bean("clasAText")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("clsBText")
public String getSomething() {
return "somethingB";
}
}
2. (Optional) Add qualifier metadata
1.10.5. Defining Bean Metadata within Components
#Configuration
public class ClsA {
#Bean("clasAText")
#Qualifier("clsA")
public String getSomething() {
return "somethingA";
}
}
#Configuration
public class ClsB {
#Bean("clsBText")
#Qualifier("clsB")
public String getSomething() {
return "somethingB";
}
}
3-1. Inject by name
1.9.7. Injection with #Resource
#Component
public class MyComponent {
#Resource(name = "clasAText")
private String text;
// ...
}
Note:
if you intend to express annotation-driven injection by name, do not primarily use #Autowired (snip). Instead, use the JSR-250 #Resource annotation
3-2. Inject by qualifier
1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers
If qualifiers have been added, these are available.
#Component
public class MyComponent {
#Autowired
#Qualifier("clsA")
private String text;
// ...
}
This answer is a fallback behavior. Name and qualifier are different one.
1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers
For a fallback match, the bean name is considered a default qualifier value.

Spring Abstract class #Autowire null while using that field in subclass constructor

Following is the code:
public abstract class A {
#Autowired
public Provider provider;
}
#Component
public class B extends A {
B() {
provider.get();
}
}
Spring is throwing NullPointerException, while instantiating Bean of Class B.
I know #Autowired defined in Abstract class are injected, but don't know in which order they are injected.
Earlier my understanding was, While instance creation of B, Spring will autowire fields of all subclasses and then will create instance of B.
But here it seems, it overlooks the subclass concept while instance creation, and just scans B to identify #Autowire field.
Use #PostConstruct. Java Object Instantiation and Spring Dependency Injection are two different flows.
#Component
public class B extends A {
#PostConstruct
void init() {
provider.get();
}
}
If autowiring your constructors is an option the following can be helpful.
public abstract class A {
protected final Provider provider;
#Autowired
public A(Provider provider) {
this.provider = provider;
}
}
#Component
public class B extends A {
#Autowired
B(Provider provider) {
super(provider);
provider.get();
}
}
Note since the latest Spring Versions you do not need to annotate the constructor with #Autowire. If you do things right the spring framework auto-detects the constructor.

Spring can you autowire inside an abstract class?

Spring is failing to autowire my object? Is it possible to autowire an object within an abstract class. Assume all schemas are supplied in application-context.xml
Question: What annotation should be on the base and extending classes (if any) #Service #Component?
Example
abstract class SuperMan {
#Autowire
private DatabaseService databaseService;
abstract void Fly();
protected void doSuperPowerAction(Thing thing) {
//busy code
databaseService.save(thing);
}
}
Extending class
public class SuperGirl extends SuperMan {
#Override
public void Fly() {
//busy code
}
public doSomethingSuperGirlDoes() {
//busy code
doSuperPowerAction(thing)
}
application-context.xml
<context:component-scan base-package="com.baseLocation" />
<context:annotation-config/>
I have that kind of spring setup working
an abstract class with an autowired field
public abstract class AbstractJobRoute extends RouteBuilder {
#Autowired
private GlobalSettingsService settingsService;
and several children defined with #Component annotation.
Normally, Spring should do the autowiring, as long as your abstract class is in the base-package provided for component scan.
See this and this for further reference.
#Service and #Component are both stereotypes that creates beans of the annotated type inside the Spring container. As Spring Docs state,
This annotation serves as a specialization of #Component, allowing for
implementation classes to be autodetected through classpath scanning.
What if you need any database operation in SuperGirl you would inject it again into SuperGirl.
I think the main idea is using the same object reference in different classes.
So what about this:
//There is no annotation about Spring in the abstract part.
abstract class SuperMan {
private final DatabaseService databaseService;
public SuperMan(DatabaseService databaseService) {
this.databaseService = databaseService;
}
abstract void Fly();
protected void doSuperPowerAction(Thing thing) {
//busy code
databaseService.save(thing);
}
}
#Component
public class SuperGirl extends SuperMan {
private final DatabaseService databaseService;
#Autowired
public SuperGirl (DatabaseService databaseService) {
super(databaseService);
this.databaseService = databaseService;
}
#Override
public void Fly() {
//busy code
}
public doSomethingSuperGirlDoes() {
//busy code
doSuperPowerAction(thing)
}
In my opinion, inject once run everywhere :)
In my case, inside a Spring4 Application, i had to use a classic Abstract Factory Pattern(for which i took the idea from - http://java-design-patterns.com/patterns/abstract-factory/) to create instances each and every time there was a operation to be done.So my code was to be designed like:
public abstract class EO {
#Autowired
protected SmsNotificationService smsNotificationService;
#Autowired
protected SendEmailService sendEmailService;
...
protected abstract void executeOperation(GenericMessage gMessage);
}
public final class OperationsExecutor {
public enum OperationsType {
ENROLL, CAMPAIGN
}
private OperationsExecutor() {
}
public static Object delegateOperation(OperationsType type, Object obj)
{
switch(type) {
case ENROLL:
if (obj == null) {
return new EnrollOperation();
}
return EnrollOperation.validateRequestParams(obj);
case CAMPAIGN:
if (obj == null) {
return new CampaignOperation();
}
return CampaignOperation.validateRequestParams(obj);
default:
throw new IllegalArgumentException("OperationsType not supported.");
}
}
}
#Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
#Override
public void executeOperation(GenericMessage genericMessage) {
LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
}
}
Initially to inject the dependencies in the abstract class I tried all stereotype annotations like #Component, #Service etc but even though Spring context file had ComponentScanning for the entire package, but somehow while creating instances of Subclasses like CampaignOperation, the Super Abstract class EO was having null for its properties as spring was unable to recognize and inject its dependencies.After much trial and error I used this **#Configurable(dependencyCheck = true)** annotation and finally Spring was able to inject the dependencies and I was able to use the properties in the subclass without cluttering them with too many properties.
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
I also tried these other references to find a solution:
http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
Using abstract factory with Spring framework
Spring Autowiring not working for Abstract classes
Inject spring dependency in abstract super class
Spring and Abstract class - injecting properties in abstract classes
Spring autowire dependency defined in an abstract class
Please try using **#Configurable(dependencyCheck = true)** and update this post, I might try helping you if you face any problems.

Resources