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