I have declared following list using spring util namespace in my spring configuration file:
<util:list id="childList">
<ref bean="child1"/>
<ref bean="child2"/>
<ref bean="child3"/>
</util:list>
where all reference bean are marked with #Componant annotation and their respective beans are creating. But whenever I am trying to Autowired any beans property like:
#Component
public class ListTest{
#Autowired
#Qualifier("childList")
private List<IParent> list;
public List<IParent> getList() {
return list;
}
}
Gives exception as: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'listTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.List com.spring3.componentScanFilterTest.ListTest.list; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring3.componentScanFilterTest.IParent] found for dependency [collection of com.spring3.componentScanFilterTest.IParent]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=childList)}
But instead of #Autowired and #Qualifier if I use as:
#Resource(name="childList")
It works. Why? As per my understanding #Autowired is used to autowire the property matching by type and #Qualifier is used to select any one bean from multiple ambiguous beans.
Please explain.
Spring docs says.
As a specific consequence of this semantic difference, beans that are themselves defined as a collection or map type cannot injected through #Autowired, because type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection or map bean by unique name.
Hope this clear your doubt.
Type matching is not properly applicable to beans which defined as collection.
If you intend to express annotation-driven injection by name, do not primarily use #Autowired - even if is technically capable of referring to a bean name through #Qualifier values. Instead, prefer the JSR-250 #Resource annotation which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.
As a specific consequence of this semantic difference, beans which are themselves defined as a collection or map type cannot be injected via #Autowired since type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection/map bean by unique name.
Here:
http://docs.spring.io/spring/docs/2.5.x/reference/beans.html#beans-autowired-annotation-qualifiers
You are trying to get list of all beans of type Parent that have the qualifier "childList".
Related
I have a abstract bean "home", a child bean "homechild" and a bean "my" to be injected in the parent. I tried to autowire the "my" bean in the parent. But it does not happen. Is this because autowiring in a abstract bean is not possible?
<bean id="home" class="my.test.own.spring_book_ch3.HomeImpl"
autowire="byType" abstract="true"/>
<bean id="homechld" parent="home"/>
<bean id="my" class="my.test.own.spring_book_ch3.MyImpl"/>
When I explicit inject, it works.
<bean id="home" class="my.test.own.spring_book_ch3.HomeImpl"
autowire="byType" abstract="true">
<property name="my" ref="my"/>
</bean>
Short answer is No, abstract parent bean cannot use autowire for injection.
From spring's reference document the child bean dictates the autowire mode
A child bean definition inherits scope, constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any scope, initialization method, destroy method, and/or static factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, lazy init.
Also the container ignores the abstract beans from instantiation thus no question of autowiring any dependencies.
ApplicationContext pre-instantiates all singletons by default. Therefore, it is important (at least for singleton beans) that if you have a (parent) bean definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set the abstract attribute to true, otherwise the application context will actually (attempt to) pre-instantiate the abstract bean.
I have following test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:ApplicationContext.xml")
public class CompoundServiceImplTest {
#Autowired
#Qualifier("testCompoundService")
private TestCompoundService testCompoundService;
//...
}
and ApplicationContext contains:
<bean id="testCompoundService" autowire="byType"
class="myPackage.TestCompoundService">
</bean>
If also tried autowire byName or leaving #Qualifier away (I added that because it did not work but that did not help either).
I get following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [myPackage.TestCompoundService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true),
#org.springframework.beans.factory.annotation.Qualifier(value=testCompoundService)}
The bean is clearly configure yet spring claims it isn't?
How can i solve this?
EDIT:
When I change #Autowired to #Resource I get following error:
Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'testCompoundService' must be of type [myPackage.TestCompoundService],
but was actually of type [$Proxy68]
The solution:
http://blog.nigelsim.org/2011/05/31/spring-autowired-use-interfaces/
TestCompoundService was a concrete class. Solution is to create an interface and use that in code and onyl in spring configuration use concrete class TestCompoundServiceImpl.
i have a little trouble in Spring with two component of a service.
I have this component:
#Component
public class SmartCardWrapper
and this one:
#Component
public class DummySmartCardWrapper extends SmartCardWrapper
The service autowire both but spring fails due this expection:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.cinebot.smartcard.SmartCardWrapper] is defined: expected single matching bean but found 2: [dummySmartCardWrapper, smartCardWrapper]
Why it doesn't use class names?
That's one of the most basic concepts of Spring - Inversion of Control.
You don't need to declare your dependencies using their implementation types (to avoid coupling with implementation). You can declare them using interfaces or superclasses instead, and make Spring find the proper implementation class in the context.
In other words, bean are not distinguished by their implementation classes, because you may want to change implementation class of a bean without changing the beans that depend on it. If you want to distinguish between different beans of the same type, use logical bean names instead:
#Autowired #Qualifier("smartCardWrapper")
private SmartCardWrapper smardCardWrapper;
#Autowired #Qualifier("dummySmartCardWrapper")
private SmartCardWrapper dummySmardCardWrapper;
I am trying to create a bean and than trying to inject the same in my Controller but i am getting bean creation failure error.Here is my code
#Service("springSecurityLoginServiceImpl")
public class SpringSecurityLoginServiceImpl implements SpringSecurityLoginService
{
//impl
}
this is how i am trying to inject it in my controller
#Controller
#RequestMapping("springSecurity/login.json")
public class SpringSecurityLoginController
{
#Autowired
#Qualifier("springSecurityLoginServiceImpl")
SpringSecurityLoginService springSecurityLoginService;
}
There is no entry in Spring-MVC-config xml file except these annotation, but when i am starting server facing the following exception
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0'
defined in ServletContext resource [/WEB-INF/config/spring-mvc-config.xml]:
Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'springSecurityLoginController':
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: com.core.servicelayer.user.SpringSecurityLoginService com.storefront.controllers.pages.SpringSecurityLoginController.springSecurityLoginService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.core.servicelayer.user.SpringSecurityLoginService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true),
#org.springframework.beans.factory.annotation.Qualifier(value=springSecurityLoginServiceImpl)}
i am not sure what i am doing wrong or what extra i have to do
SpringSecurityLoginController class refers SpringSecurityLoginService class, for which a bean isn't defined. That much the error says.
It is true, because you've only defined a bean for the class LoginServiceImpl, which doesn't seem to extend SpringSecurityLoginService in any way.
Spring's bean lookup algorithm first searches for beans of which type is, or extends, SpringSecurityLoginService. Then, it narrows the avaialble options using the Qualifier. In this case, no bean is found in the first place...
See Spring doc:
4.11.3 Fine-tuning annotation-based autowiring with qualifiers
Since autowiring by type may lead to multiple candidates, it is often
necessary to have more control over the selection process. One way to
accomplish this is with Spring's #Qualifier annotation. This allows
for associating qualifier values with specific arguments, narrowing
the set of type matches so that a specific bean is chosen for each
argument.
You need that LoginServiceImpl will implement SpringSecurityLoginService, for instance.
EDIT
Since it was just a typo you might be not including SpringSecurityLoginService's package in component-scan tag, in your spring configuration file (as gkamal has already mentioned). You should have there something like:
<context:component-scan base-package="org.example"/>
where org.example should be replaced by SpringSecurityLoginService's package.
I have a number of Spring beans, some of which are in a shared library jar. I can't seem to get #Qualifier to work.
I have default-autowire set to "byType", this is using Spring 3.1.0.M2 and running as a standalone executable. If I remove "TestTwoBean" from the shared library the project executes as expected.
myproj-shared-lib.jar:
#Service
public class TestOneBean implements ITestBean {
}
#Service
public class TestTwoBean implements ITestBean {
}
myproj.jar:
#Service
public class TestConsumerBean {
#Autowired #Qualifier("testOneBean")
private ITestBean bean;
}
I get the "no unique bean with name" exception at runtime:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'testConsumerBean' defined in file [-]:
Unsatisfied dependency expressed through bean property 'bean': : No
unique bean of type [com.myco.ITestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean]; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.myco.TestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean] at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1167)
...
Does #Qualifier not work in this situation? Is there a known workaround?
Are you sure you want to use autowire by type AND annotation injection? Autowire by type means spring will attempt to inject detected setters and constructor parameters using by type lookup even if they aren't annotated for injection.
At the same time you are trying to inject fields by name. Your #Service annotated classes produce beans with names defaulting to the class name, "testOneBean" and "testTwoBean" respectively. #Qualifier uses bean names as correct matches. The recommended way of doing "by name" injection though is by using #Resource(name="testOneBean"). I can only guess spring tries injection by type due to autowire mode set to by type (which I doubt you really need).
I would recommend reverting to default autowire mode and using #Resource for wiring by name.