Spring #Qualifier not working when bean is in another jar file - spring

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.

Related

Bean's property is not setting from util:list object

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".

Unable to wire using ActiveProfile annotation

First time using Profiles and need help.
I have an abstract base class (DecisionManagementRuleExecutor) that gets its dependency (RuleHandler) wired through annotation.
#Component
public class RuleHandler {......
public abstract class DecisionManagementRuleExecutor<M extends PersistentEntity,T extends Response> implements RuleExecutor<M,T>{
#Autowired
RuleHandler ruleHandler;
When I run with 'itest' profile, I want 'ITestRuleHandler' a child of 'RuleHandler' to be wired.
Where 'ItestRuleHandler' is
#Component
#ActiveProfiles(value = "itest")
public class ITestRuleHandler extends RuleHandler {
I see that in the logs that active profile is 'itest'
System.getProperty("spring.profiles.active")
I am pasting the log for the wiring
Processing injected element of bean 'vendorServiceRuleExecutor': AutowiredFieldElement for c.a.p.d.RuleHandler c.a.p.d.s.DecisionManagementRuleExecutor.ruleHandler
Returning cached instance of singleton bean 'ITestRuleHandler'
Creating shared instance of singleton bean 'ruleHandler'
Creating instance of bean 'ruleHandler'
Eagerly caching bean 'ruleHandler' to allow for resolving potential circular references
Finished creating instance of bean 'ruleHandler'
Autowiring by type from bean name 'vendorServiceRuleExecutor' to bean named 'ruleHandler'
Finished creating instance of bean 'vendorServiceRuleExecutor'
Edit:
Changed the 'RuleHandler' as an interface and now I am getting this error:
No qualifying bean of type [c.a.p.d.RuleHandler] is defined: expected single matching bean but found 2: ITestRuleHandler,iTestRuleHandler
To make the implementation ITestRuleHandler available for the itest profile, you need to declare your class as:
#Component
#Profile("itest")
public class ITestRuleHandler extends RuleHandler
#ActiveProfiles activates one or more profiles, not expose a component for a profile. This should be applied to one of the test (or consuming) classes to activate a profile for testing (or consumption).

spring-data autowiring not working

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.

Spring No unique bean of type

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;

Bean creation is failing (spring)

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.

Resources