In Spring, is it possible to avoid a NoUniqueBeanDefinitionException in the following scenario:
My application references beans in a 3rd party library
appBean="thirdPartyClass"
The bean code is in a 3rd party library I can't edit
#Component
public class ThirdPartyClass {
#Autowired
private ThirdPartyInterface thirdPartyInterface;
The third party interface is used by two classes I do control
This class:
public class MyClass1 implements ThirdPartyInterface {
and this class:
public class MyClass2 implements ThirdPartyInterface {
Currently, NoUniqueBeanDefinitionException is occurring when I try to start my application saying the following:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'thirdPartyClass': Unsatisfied dependency expressed through field 'thirdPartyIntereface'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'ThirdPartyInterface' available: expected single matching bean but found 2: MyClass1,MyClass2
Considering you cannot change the ThirdPartyClass class.
Make one of the implemented classes as #Primary to be considered as the primary bean to be Autowired in the ThirdPartyClass class.
#Primary
#Component
public class MyClass1 implements ThirdPartyInterface {
}
And add #Qualifier to the other implemented class. And use that same qualifier in your other classes to Autowire and use it seamlessly.
#Component
#Qualifier("queue2")
public class MyClass2 implements ThirdPartyInterface {
}
#Component
public class MyOtherClass {
#Autowired
#Qualifier("queue2")
private ThirdPartyInterface thirdPartyInterface;
}
The error clearly says what the problem is -
When you have 2 class implementing same interface and you are trying to use #Autowired via the interface, Spring does not know which implementation to pick (MyClass1 or MyClass2).
You need to be specific. Use #Qualifier to specify which implementation to pick.
I quickly found one example here - Spring #Autowired and #Qualifier
Related
I have a MyService class which has repository field supposed to be injected.
public class MyService {
#Autowired
private MyRepository repository;
// ...ommited
}
And there is MyRepository interface only implemented by MyRepositoryImpl class with #Mapper annotation of MyBatis.
public interface MyRepository {
// ...ommited
}
#Mapper
public interface MyRepositoryImpl extends MyRepository {
// ...ommited
}
When I try to start SpringBootApplication, NoUniqueBeanDefinitionException is thrown.
#SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
#MapperScan(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
(...omitted)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.example.MyService':
Unsatisfied dependency expressed through field 'repository';
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.example.MyRepository' available:
expected single matching bean but found 2: com.example.MyRepositoryImpl,com.example.MyRepository
(...omitted)
Why is MyRepository interface registered as one of bean even though it doesn't have #Component annotation nor isn't included any bean configurations?
And I found that everything work fine if I don't use FullyQualifiedAnnotationBeanNameGenerator as nameGenerator.
Any ideas?
There can be many other ways to mark an interface as a bean. Some of them are:
#RepositoryDefinition above MyRepository interface
MyRepository extends CrudRepository or JpaRepository
Check if any of these exist.
Update 1:-
The problem seems to be in #MapperScan. What it does is scans for all the interfaces in a package and register them as bean; and if I am not wrong MyRepository and MyRepositoryImpl are in the same package. That's the reason why 2 beans are being created with names com.example.MyRepositoryImpl, com.example.MyRepository and basically both are of same type as MyRepositoryImpl extends MyRepository.
Now when you are using #Autowired on repository field of MyService, it gets confused as in which one to inject. To resolve this the easiest approach is to use #Primary over MyRepositoy which will give that interface a priority while injecting. Another approach is to use #Qualifier("uniqueName") over both the interfaces and also above repository field of MyService along with #Autowired specifying which one you want to inject. You can visit official documentation from here to learn more.Hope this helps a bit .
Spring is not able to figure out the bean whose class is supposed to be implementing the Repository interface.
Put the annotation #Repository above the RepositoryImpl Class. It will find it.
I have a classA which implements an interfaceA, with a methodA, then I have a classB in which I call classA with an #Autowired to be able to use methodA, but it gives me a warning that I must create a method for classA. Why is this happening? Doesn't #Autowired work like this in this case? Should I just instantiate classA? Thank you very much for your answers.
ClassA
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice springDataColminvoice;
#Override
public <S extends TransactionDto> S save(S s) {
Colm colm = transactionDataMapper.toEntity(s);
//methodA
springDataColminvoice.save(colm);
return null;
}
}
InterfaceA
public interface IRepository extends IRepository<TransactionDto, Integer> {}
ClassB
#Service
#RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService {
#Autowired
private RepositoryImpl repositoryImpl;
#Override
public void save(CMessage cMessage) throws HandlerException {
try {
TransactionDto transactionDto = cMessage.getTransaction();
// methodA
repositoryImpl.save(transactionDto);
} catch (Exception e) {
throw new HandlerException(e.getMessage());
}
}
}
Exception
Action:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.
(posting this as an answer since I do not have enough reputation to comment)
As others have pointed out already, a code sample would help tremendously.
That being said, though, it sounds like you're missing implementation for "ClassA".
If you have an interface that "ClassA" implements, you have to implement the interface's methods in "ClassA" before you can use them.
I assume your code currently looks somewhat like this?
public interface InterfaceA {
void methodA();
}
public class ClassA implements InterfaceA {
}
public class ClassB {
#Autowired
ClassA classA; // Cannot use {#link InterfaceA#methodA} because the class does not implement the function
}
If this is your code, make sure you add an implementation for your "methodA()" function in "ClassA". Somewhat like so:
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Additionally, in order to autowire in Spring (Boot), you need to ensure that the class you'd like to autowire is marked as such. You can autowire beans.
To make "ClassA" in the example eligible for autowiring, make sure to instantiate it either as:
A bean (using the #Bean annotation).
A component (using the #Component annotation).
A service (using the #Service annotation).
Any of the other annotations that may match your use case the best.
In our example, this would look somewhat like this:
#Component // Or #Service / whatever you may need
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Hope you've found any of this helpful. All the best!
-T
As what I have understood, #Autowire means injecting the value/instance of the specific property where you put the annotation #Autowire. In this case, #Autowire only happens when there is defined/created Bean within your basePackage of your Spring Boot project that can match it, i.e. where your #Autowire referred to (meaning there is no conflict issue like ambiguity, etc. and the DataType(Class) can be implicitly casted). In your example, first you treat the IRepository and/or RepositoryImpl as Repository without using the #Repository annotation to inform the Spring Boot default configuration that this is a Repository bean. As you didn't put the POM.xml or posted the related code, I presumed you are creating your own repository class. I think it's much better to post your dependencies here.
But as what others pointed out. You need to create a bean that can match the #Autowired you've put on TransactDataManager & SpringDataColminvoice. You need also to inform the Spring Boot or register it that your class A is a Bean by annotating
#Bean - defining a regular bean,
#Component - a Component in the Project,
#Service - a Service in the Project,
#Repository - a Repository (if you're using Spring JPA), etc.
#<Other Annotations depending of what other Spring Project/Dependencies your using>
Since newer versions of Spring is moving to annotation based from XML mapping, we need to put proper annotation for each class/object that we want to be auto injected/instantiated from #Autowired using the above sample annotations depending on the role/purpose of your class/object is.
I suggest if you're not sure. Then create a typical bean using common annotation #Bean. So your class A might be
#Component //Insert proper Annotation for your class if necessary. This is just a sample
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice
springDataColminvoice;//segunda
#Override
public <S extends TransactionDto> S save(S s) {
//Some implementation
}
#Bean
private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>){
return <an instance for TransactionDataManager>;
}
#Bean
private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>){
return <an instance for SpringDataColminvoice>;
}
}
Note that 2 beans definition are optional if there are already a Beans define on outside class or if it was marked by other annotation like #Service, #Component or other proper annotations and the other one bean is just a reference parameter for the other bean in order to properly instantiated.
In your class B is the following:
public class ClassB {
#Autowired
ClassA classA;
/*Note: ignore this Bean definition if Class A is annotated with #Component,
#Service, or other proper #Annotation for Class A.
*/
#Bean
private ClassA getClassA(<Some Parameters if Needed>){
return <Instance of Class A>
}
}
Take note that, you don't need to put a Bean definition inside the Class B if you put a proper annotation for your Class A like #Component, #Service, etc.
I am trying to migrate a Spring 4.x.x to Spring boot and it has a dependency on a class in external spring 2.5 jar. I have made all the autowiring changes and below is my application class
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages = { "com.xyz" })
public class MainApiApplication {
public static void main(String[] args) {
SpringApplication.run(MainApiApplication.class, args);
}
}
The dependent class in the external jar is present under the package com.xyz.abc because of which I have placed my main application class under com.xyz package and also added the component scan under the same package
Here are my component classes with the dependency autowired
#Component
public class ComponentClassA {
#Autowired
private ComponentClassB currencyService;
}
#Component
public class ComponentClassB {
#Autowired
private DependentClass depClass;
}
DependentClass is the class present in the external dependent jar which I have locally attached and built
When building the application, compilation of all files is fine and build is generated successfully. But when I start the application, I get the below error
Field DependentClass in com.xyz.ComponentClassB required a bean of type 'com.xyz.common.util.DependentClass' that could not be found.
I don't understand the reason for the class from external jar being not found as I have added component scan for the package
The definition of DependentClass is like below
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}
Is it because DependentClass is extending a class ? Can someone help me figure out the reason for the error ?
The DependentClass does not have #Component annotation on it. So, you need to create a bean of DependentClass yourself either via XML or Java config.
And it is not necessary that you place your main class under the same package as DependentClass.
Define your class as per below:-
#Component("depClass")
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}
Component register it into your context defination if this package lie into your ScanBasePackages and the depClass inside the component annotation define the name of your bean.
you can also call it by:-
#Autowired
#Qualifier("depClass")
private DependentClass dependentClass;
If that class define in your external class then use #Bean annotaion like:-
#Bean
public DependentClass depClass(){
return new DependentClass();
}
After that Autowired the class you get the instance finally.
DependentClass is not defined in your current Spring Context.DependentClass is not annotated with a bean (#Bean).Hence nosuchbeandefinitionexception occurs.
#Bean
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}
I have this pair of daos:
package com.company.project.model.requests.type;
#Repository("requestTypeDao")
public class RequestTypeDaoHibernate extends AbstractReadDao implements RequestTypeDao {
}
package com.company.project.model.support.type;
#Repository("requestTypeDao")
public class RequestTypeDaoHibernate extends AbstractReadDao implements RequestTypeDao {
}
and I'm trying to inject them in some XXXServiceImpl classes (never both in the same class) like this:
#Autowired
private RequestTypeDao requestTypeDao;
Because they are not the same type, I was expecting Spring to inject based on the imported type from the corect package (there are never imported two RequestTypeDao from the same package), but it shows an error:
Annotation-specified bean name 'requestTypeDao' for bean class [com.company.project.model.support.type.RequestTypeDaoHibernate] conflicts with existing, non-compatible bean definition of same name and class [com.company.project.model.requests.type.RequestTypeDaoHibernate]
At the error you can see the class is not the same. I have read about the #Qualifier annotation but I understand it would imply changing the name in written in the #Repository annotation. I also think that #Resource or #Inject are not what I looking for.
We don't mind changing names in the end, but we want to know if real injection by type can be made through Spring. This is two repositories with same name and different class types and packages being injected in distinct and different classes (never the same one).
Actually this is impossible. There's no way to register two same named beans into the spring. You have to use #Qualifier Otherwise spring can't handle which bean you want in the runtime.
You can learn more here
#Autowired
#Qualifier("personA")
private Person person;
#Autowired
#Qualifier("personB")
private com.blabla.myOtherPackage.Person person;
I would like to autowire a component (still using the #Autowired annotation), but not require it to have the #Component (or other similar annotations) on it. How would I do this?
public class A {
#Autowired
private class B b;
}
#Component
public class B {
}
This would be convenient in order to allow autowiring of class A without requiring the creation of A, unless we needed it (in otherwise on the fly by reflection using the class name).
Injection and autowiring do not require #Component. They require beans. #Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a #Bean method in a #Configuration class, etc.
Your last sentence doesn't make much sense. You can't process injection targets in a bean without creating a bean. You also can't inject a bean without creating it. (Applied to scopes, bean may refer to the target source/proxy and not the actual instance.) Perhaps you want #Lazy.
I don't sure, If I correctly understood to your question. But if you want inject bean B without marking bean A via some annotation, or xml definition, you can use SpringBeanAutowiringSupport
public class A {
#Autowired
private class B b;
public A{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}