Spring No unique bean of type - spring

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;

Related

#MockBean injected into a constructor-autowired component

From the official documentation:
When registered by type, any existing single bean of a matching type (including subclasses) in the context will be replaced by the mock
What if the service under test is autowired in the constructor, though? E.g. in Kotlin (I suppose #MockkBean and #MockBean work the same regarding DI):
#RunWith(SpringRunner.class)
class ExampleTests #Autowired constructor(val userOfService: UserOfService) {
#MockkBean
private lateinit var service: ExampleService
...
}
I would expect this example to fail because in order to instantiate ExampleTests Spring has to first obtain a proper instance of UserOfService. That shouldn't be possible at that time, though, because there's no bean of type ExampleService in the application context yet.
Contrary to my expectation, this works. How is it possible?
Because you miss the other part from the documentation :
In either case, if no existing bean is defined a new one will be
added.
So #MockBean will also instantiate a bean automatically if that bean is not found in the spring context.
The sequence of actions are mainly as follows :
Start up the spring context which create all the spring BeanDefinition only that are registered in the spring context.
Process #MockBean which will replace the BeanDefinition in (1) or create a new BeanDefinition
Actually instantiate all the beans based on these BeanDefinition. It will handle which bean to be actually instantiated first and later.
Create a test instance (i.e ExampleTests) to execute its test methods. If any beans required to be auto-wired into the test instance are not created , it will fail.
So as long as you define UserOfService bean , ExampleTests can be instantiated as you are now using #MockBean on the ExampleService which means it must exist no matter you define it or not in the spring context for the test.

Is it still loose coupling if we use #qualifier

we use interface for autowiring service into controller
this is for loose coupling , coz the interface can hold object of any of its implementations. so no need to write the implementation name and create tight coupling.
however when we have more than one implementations for an interface, we write the #qualifier .
my question is if we have to write qualifier to tell which implementation needs to be injected, then should we still call it loose coupling??
class ServiceInterface {
interfaceMethod();
}
implementation 1:
#component("service1")
class ServiceImpl1 implements ServiceInterface {
interfacemethod(){
}
}
implementation 2:
#component("service2")
class ServiceImpl2 implements ServiceInterface {
interfaceMethod(){
}
now only instead of directly creating Object of ServiceImpl1() using new
ServiceImpl1 obj = new ServiceImpl1();
we write in
class Controller {
#autowired
#qualifier("service1")
ServiceInterface se;
sc.interfaceMethod();
}
Partially yes, because the component that uses the injected qualified bean still didn't create it or handle its lifecycle.
But indeed using #Qualifier creates some sort of coupling. If you want to avoid this, consider making one of your ServiceInterface beans the primary implementation for the interface annotating its class with #Primary as follows:
#Component
#Primary
class ServiceImpl1 implements ServiceInterface {
interfacemethod(){
}
}
With this, every time you need a ServiceInterface implementation but you don't actually specify which one you want (using #Qualifier) the primary one is injected by Spring.
Even though you are using the #Qualifier annotation you are still using inversion of control to let the framework manage your dependencies.
Furthermore, lets say you wouldn't autowire this implementation but use 'new' to create your object.
When the implementation changes you would need to update all the places where this is created. However, with dependency injection you wouldn't need to do so. Therefore you still have the advantages of dependency injection with regards to loose coupling.
If you would like to have your implementation less coupled with your target class then you could do a few things
Use #Primary for a bean to determine the default implementation.
Autowire your implementations into a List<ServiceInterface>
Use Spring's ObjectFactory to determine which bean to use at runtime
Use Profiles to determine which bean to autowire

How to inject Spring's Validator implementation?

I started with generating my application using JHipster v.3.5.1.
After some time, I needed to create validator to perform some business logic validation on my entity, when it is created with POST. So I made:
#Component
public class MyValidator implements Validator
Then, I tried to inject it into my controller (annotated with #RestController), but no matter which way I tried, it always resulted in something like that:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.my.app.service.domain.MyValidator] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Ways I tried to create bean and inject it
#Autowired
private MyValidator myValidator;
#Inject
private MyValidator myValidator;
#Autowired
#Qualifier("myValidator")
private MyValidator myValidator; (with #Component("myValidator") on class)
#Inject
#Qualifier("myValidator")
private MyValidator myValidator; (with #Component("myValidator") on class)
//Below was inserted in class annotated with #Configuration
#Bean
public MyValidator myValidator() {
return new MyValidator();
}
However I tried it - it failed. I always got NoSuchBeanDefinitionException or field value was set to null.
I've also checked class location in project structure. To be 100% percent sure it's well placed, I've put it in package the with #Services, which are scanned and work well. No effect.
I know that it seems to be pretty easy task and I know this injection is possible (I've seen it done in project in my work), but somehow I'm not able to make it work in my project.
Maybe I'm missing something in configuration? Thanks for any help :)
I believe your issue is that when you use #Autowired inside a class annotated with #Configuration you are just referencing to a bean that is defined in a separate configuration file, that is it has to be declared in another file also with the #Configuration annotation.
If you want to refer refer to another implicit bean such as your validator annotated with #Component you will need to do it in another implicit bean also annotated to with implicit notation such as #Component, #Service, #Controller, etc
The #Autowired alone should work unless you have more than one class implementing the same interface. That is when you will need to use the #Qualifier.

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

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.

Spring DI? Interface Type?

I understand the how, but can't seem formally shape the definitions.
As known DI can be done via constructor or setter or interface.
I am confused about the latest one -interface based DI, is it used in Spring?
UPDATE: I gave bad examle in here, which led to wrong understanding.
To fix it up:
Say we have setter and in setter we inject interface implemented by some class. Is that considered DI via setter or interface?
http://martinfowler.com/articles/injection.html#UsingAServiceLocator
this article divides DI on:
"There are three main styles of dependency injection. The names I'm using for them are Constructor Injection, Setter Injection, and Interface Injection. If you read about this stuff in the current discussions about Inversion of Control you'll hear these referred to as type 1 IoC (interface injection), type 2 IoC (setter injection) and type 3 IoC (constructor injection). I find numeric names rather hard to remember, which is why I've used the names I have here."
Else Service Locator pattern used for IoC, is it the one that actually makes possible #Autowired? - ie that not all classes explicitly need to be declared in xml for DI, as we can declare them as #Repository or #Controller or alike again if I recall correctly.
Thanks,
Autowiring an interface means wire a bean implementing that interface. This relies on an implementation actually existing in the bean factory.
#Autowired
UserService us; // wire a bean implementing UserService
--
#Service
public class UserServiceImpl implements UserService {
// the #Service annotation causes this implementation of UserService to
// be made available for wiring in the bean factory.
}
Worth noting is that if you wire by interface, Spring will expect there to exist one and exactly one bean in the bean factory implementing that interface. If more than one bean is found, an error will be thrown and you will have to specify which bean to wire (using the #Qualifier annotation).
EDIT:
When wiring, you can either wire a member variable or a setter method.
#Autowired
UserService us;
--
#Autowired
public void setUserService(UserService us) {
this.us = us;
}
These two produce the same result. The difference is that in the former, Spring will use reflection to set the variable us to a bean implementing UserService. In the latter, Spring will invoke the setUserService method, passing the same UserService imlementation.

Resources