avenue68
avenue68

Reputation: 53

NoUniqueBeanDefinitionException thrown though there is only one implementation

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?

Upvotes: 0

Views: 767

Answers (2)

S.Ashok
S.Ashok

Reputation: 119

There can be many other ways to mark an interface as a bean. Some of them are:

  1. @RepositoryDefinition above MyRepository interface
  2. 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 .

Upvotes: 1

Napstablook
Napstablook

Reputation: 614

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.

Upvotes: 0

Related Questions