How do I #Autowire to an extended class when #Qualifier is used in Spring? - spring

I have the following classes:
public class Service
{
#Autowired
#Qualifier(Helper.BEAN_NAME)
protected Helper helper;
...
}
#Component(Helper.BEAN_NAME)
public class Helper
{
public static final String BEAN_NAME = "Helper";
...
}
#Component(Helper.BEAN_NAME)
public class ExtHelper extends Helper
{
...
}
My goal is to not touch the Service or Helper classes. My thinking is that by giving ExtHelper the same bean name as Helper, Spring will autowire ExtHelper implementation to Service instead of Helper.
I am seeing mixed results with this. If ExtHelper is included in my pom AFTER Helper, it works ok. But before, I get a ConflictingBeanDefinitionException. I understand the exception, but not why I get it if I swap the order of dependencies in the POM.
My basic question is whether I am doing this correctly conceptually. Is #Qualifier intended to prevent this kind of override of autowiring? If not, what is the rule to make Spring resolve the conflict by choosing my extension over the base class? Am I required to extend the Service class to get what I want? I am new to Spring and don't quite get how I am supposed to be doing this.

#Qualifier is intended to be used to instruct Spring which bean should be injected in case of multiple beans of type available.
In your case you have two beans that could be injected into protected Helper helper attribute so you have to tell Spring which one should be used. You can't do it with #Qualifier as both of the beans have the same name.
If you don't want to touch those classes you could use another annotation to prioritise a bean - #Primary. Add it on ExtHelper and it will be treated as a preferred bean in case of multiple bean available for injection.
If you want to stay with #Qualifier you would need to change name of one of those beans and inject preferred bean:
#Component
public class Service
{
#Autowired
#Qualifier("extHelper")
protected Helper helper; // instance of Helper or ExtHelper could be injected here
...
}
#Component // bean will be named using default naming strategy: helper. You can obviously use your own name
public class Helper
{
...
}
#Component // bean will be named using default naming strategy: extHelper. You can obviously use your own name
public class ExtHelper extends Helper
{
...
}

Related

when using functional bean registration, is there a way to inform Spring that ClassA is responsible for creating an instance of BeanA?

I've switched a portion of a Spring app to use functional bean registrations. The motivation for the switch is due to requiring multiple instances of some beans under certain conditions. It also turns out to be much more concise (which won't be at all apparent with the simplistic examples below).
The code used to look like this (simple example):
#Configuration
public class ConfigA {
#Bean
public BeanA beanA() {
return new BeanA();
}
}
#Service
public class Service1 {
#Autowired BeanA beanA;
...
}
#Service
public class Service2 {
#Autowired BeanA beanA;
...
}
I've switched the configuration class to look like this:
#Configuration
public class ConfigA implements ApplicationContextInitializer<GenericApplicationContext> {
#Override
public void initialize(GenericApplicationContext context) {
context.registerBean("beanA", BeanA.class, () -> new BeanA());
}
}
The issue I'm now encountering is that Spring is complaining about autowired beans not being found. With the original code, Spring could determine that a BeanA bean was declared via ConfigA and would create that bean before initializing the services.
With the new code, I guess there is no way for Spring to determine where the BeanA bean(s) are being declared, and so it tries to init the services before the BeanA is initialized (which causes the app to not start).
I was hoping that Spring would prioritize #Configuration classes over #Service or #Controller classes, but that doesn't seem to be the case.
I could annotate all the services with #DependsOn("configA"), but there are many services that autowire BeanA (some in other code bases), so the #DependsOn option isn't really realistic.
Question: When using functional bean registration, is there a way to inform Spring that ConfigA is responsible for creating an instance of BeanA?
In order to use the functional style of bean registration and enable autowiring mechanism in other beans you can do the following:
Remove #Configuration annotation from your ConfigA class;
Create directory named META-INF under main/java/resources and create a file named spring.factories under the newly created directory;
Fill the newly created file with the line org.springframework.context.ApplicationContextInitializer=(package-name-to-configA-class).ConfigA
Now Spring should be able to successfully autowire bean named BeanA where requested.

Not able to inject values in a field

#Component
#PropertySources({ #PropertySource("classpath:mail.properties") })
public class A implements B {
#Value("${mail.team.address}")
private String teamAddress;
// has getter and setters .not shown for brevity.
Now when i call the class i get the value of teamAddress as NULL .But in the property file mail.team.address has some value.
My property file is present under src/main/resource folder
Making a call
A a = new A ();
a.someMethodinClassA();
You can not create instance of class by yourself when you want Spring to resolve #Value annotation.
See documentation:
Note that actual processing of the #Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use #Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
Simple solution for you: just annotate class with any #Component annotation and let Spring to create an instance of your class.
You can't create (with a "new" keywoard) for spring bean. If you do it like this, spring doesn't participate in the object creation and configuration, which means that there is no autowiring, the bean is not in Application Context, etc. And of course, #Value annotation won't be processed among other things
The better way is to inject the class A to the code that you used in your example:
A a = new A ();
a.someMethodinClassA();
Show become:
#Component
public class SomeClass {
private final A a;
public SomeClass(A a) {
this.a = a;
}
public void foo() {
a.someMethodinClassA();
}
}
You should read some basics around spring dependency injection. The class that you have autowired with #Component is scanned via component scanning and its object is created by spring container for you.
that is the reason you should not create the object yourself using new keyword.
wherever in your new class you want to use your class A object you can autowire it as below:
#Component
public class TestC{
private A a; // this object will be injected by spring for you
}

Is #Autowired taking care of the nested autowiring?

I have the following components, in two different files:
#Component
public class Chauffeur {
Car car;
public Chauffeur(Car car){
this.car = car;
}
public void go(){
System.out.println("Chauffeur");
car.drive();
}
}
#Component
public class Car{
public void drive() {
System.out.println("Drive car");
}
}
the following configuration file:
#Configuration
#ComponentScan
public class DriveableConfiguration {
}
and the following test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=DriveableConfiguration.class)
public class DriveableTest {
#Autowired
Chauffeur chauffeur;
#Test
public void chauffeurTest(){
chauffeur.go();
}
}
All the classes above are in the same package and the test is passing.
In the test I annotated chauffer with #Autowired, which should mean that the Spring container looks after the creation of the instance of Chauffeur without the developer needing to explicitly instantiate it.
Now, the constructor for Chauffer needs an instance of Car, so there is no default constructor for that class. Nonetheless the container creates it, injecting the required instance in the constructor.
Is the #Autowired saying to the container to instantiate the element with whatever (Components, Beans) it can provide, included parameters in the constructor? If so, in what case is it needed to use #Autowired to annotate a constructor?
Only if you use Spring 4.3+. In such a case #Autowired on constructor is optional if you have one non default constructor.
You can check the example here.
So as of 4.3, you no longer need to specify an explicit injection annotation in such a single-constructor scenario. This is particularly elegant for classes which otherwise do not carry any container annotations at all, for example when programmatically registered
For versions lower than 4.3 you will an exception will be thrown:
the container will throw an exception looking for a default
constructor, unless you explicitly indicate autowire mode
‘constructor’ in your bean definition setup (e.g. in an XML )

Injecting 2 bean with same class name

I have a app 'app_test' which consists a class TestClass with #Service anotation. I have a library class 'lib_test' with bean in XML file with id=''TestClass'. Both are in different package.
I m injecting #Service bean as follows
Import com.app.TestClass
Class TestController
{
Private final TestClass testClass;
#Inject
TestController (TestClass testClass)
{
This.testClass =testClass;
}
}
It should inject by type since they are in different package. But the controller is giving qualified bean not found.
I can resolve it by giving #Qualifier and giving name to #Service. But y is it needed? Since both are in different package it should autowire by type right? Or m missing some concept?
Although they are in different packages if they are of the same type Spring does not know which to use
I'd suggest marking any service class with #Primary.
package com.app.TestClass
#Primary
#Repository
public class TestClass implements XXX
This way it will be selected as the default autowire candididate, with no need to autowire-candidate on the other bean.
Also, rather than using #Autowired #Qualifier, I find it more elegant to use #Resource for picking specific beans.
I've always found this a strange limitation of Spring's standard bean naming convention. It does not include the package part of the class in the name leading to duplicates in large projects when classes have the same name.
This is why I always configure Spring projects with a different BeanNameGenerator:
public class CustomAnnotationConfigWebApplicationContext extends AnnotationConfigWebApplicationContext {
private BeanNameGenerator qualifiedAnnotationBeanNameGenerator = new QualifiedNameAnnotationBeanNameGenerator();
#Override
protected BeanNameGenerator getBeanNameGenerator() {
return this.qualifiedAnnotationBeanNameGenerator;
}
}
And the generator:
public class QualifiedNameAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
#Override
protected String buildDefaultBeanName(BeanDefinition definition) {
String qualifiedName = definition.getBeanClassName();
return Introspector.decapitalize(qualifiedName);
}
}
With this setup, common class names that are in different packages are automatically recognized as being different and the correct one gets injected.

Autowiring doubts in spring?

After going thru autowiring concept
i have got some questions. These are:-
If i need to autowire below class byType or byName , is it mandatory to have setStudent() method in class College?
public class College {
private Student student1;
private String registration1;
}
<bean id="student1" class="Student"/> - in case of byname it will look into id attribute and in case of bytype it will look for class attribute in above
Stetement. Right? If incase it finds two bean dean tags for the same type it will throw fatal error in case of bytype. Correct?
autodetect Scenario chooses constructor or byType through introspection of the bean class. If a default constructor is found, the byType mode
will be applied.
My question here if default constructor is not found and constructor with argument is found then autowire by constructor
will be applied. Correct?
Do we need to specify #Autowired somewhere in College to apply the autowiring. As i can see this in this example
but nothing is specified here
1), 4) There are two separate ways of autowiring in Spring: XML-based and annotaion-based.
XML-based autowiring is activated from XML config, as described here. In the end, it will call setter method, so setStudent() method is required here.
Annonation-based autowiring, on the other hand, is performed via reflection magic. It attempts to fill everything you mark with #Autowired annotation. In fact, it can set private field with no accessors, as in
public class Foo {
#Autowired private Thingy thing; // No getThing or setThing methods
private void doStuff() {
// thing is usable here
}
}
For #Autowired annotaion to work, you will need to define corresponding bean post-processor; it is done by adding the following line to xml config:
<context:annotation-config/>
Note, that these two autowiring methods are independant, and it is possible(but not recommended) to use them simultaneously. In that case, xml autowiring will override annotations.
2) In general, autowiring will fail, if it cannot find one and only one candidate for injection. So, in your case, it will fail with exception upon container creation. There are some fallback quirks, but in general it works reliably.
3) Yes, documentaion says so.
About byName and byType autowiring. While byName autowiring simply tries to match bean name (can be specified with id attribute), byType is a bit more complex than class attribute lookup. It searches beans by type, and it will match interfaces. Example:
public interface SomeService {
void doStuff();
}
public class SomeServiceImpl implements SomeService {
#Override public void doStuff() {
// Implementation
};
}
public class ServiceUser {
#Autowired
private SomeService someService; // SomeServiceImpl instance goes here
}
P.S. You are referencing two different versions of Spring in your question, 2.5 and 3.0. Autowiring behavior is same in both.
In Addition if you are using #Autwired annotation you need to mark the classes as candidates for autowiring. It should be done by using one of these annotations:
#Repository
#Service
#Component
#Controller
and of cause you can configure it in different scopes:
#Scope("prototype")
#Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
Hope it makes it more clear.

Resources