TechiRik
TechiRik

Reputation: 2133

SpringBoot: Unsatisfied dependency NoSuchBeanDefinitionException, expected at least 1 bean which qualifies as autowire candidate

I am making a very silly mistake but not able to figure out how to fix.

I have a simple SpringBoot app using profiles, which connect to MongoDb.

My pom.xml dependencies:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
</dependencies>

My StudentController.java

@RestController
@RequestMapping("/students")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @RequestMapping(method = RequestMethod.GET)
    public Collection<Student> getAllStudents(){
        return studentService.getAllStudents();
    }
}

My StudentService.java

@Service
public class StudentService {

    @Autowired
    private StudentDao studentDao;

    public Collection<Student> getAllStudents(){
        return this.studentDao.getAllStudents();
    }
}

My StudentDao.java interface:

public interface StudentDao {
    Collection<Student> getAllStudents();
}

My MongoStudentDaoImpl.java:

@Repository
@Profile("test")
public class MongoStudentDaoImpl implements StudentDao {

    @Autowired
    private MongoStudentRepo repo;

    @Override
    public Collection<Student> getAllStudents() {
        return repo.findAll();
    }
}

My MongoStudentRepo.java:

@Profile("test")
public interface MongoStudentRepo extends MongoRepository<Student, String> {
}

When I am trying to start the application using the "test" profile, here is the error I am seeing:

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentController': Unsatisfied dependency expressed through field 'studentService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'studentService': Unsatisfied dependency expressed through field 'studentDao'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoStudentDaoImpl': Unsatisfied dependency expressed through field 'repo'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'MongoStudentRepo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

What am I missing in here? Do I need to add an annotation to MongoStudentRepo.java?

Thanks in advance.

Upvotes: 2

Views: 3395

Answers (4)

Ananthapadmanabhan
Ananthapadmanabhan

Reputation: 6206

The stacktrace shows that spring is not able to autowire one of the beans MongoStudentRepo in your MongoStudentDaoImpl.java class.From the stacktrace :

 Unsatisfied dependency expressed through field 'repo'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'MongoStudentRepo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 

Spring throwing this exception means that the bean of MongoStudentRepo.class is not getting created properly.

Possible solution :

  • The issue might be because spring is not creating a bean for your interface using the default implementation in spring.This might be because you are not using the annotation @EnableJpaRepositories to enable scanning and creation of default repository bean.For more information read here .

But if you are using xml based configuration, For xml based configuration use :

<repositories base-package="com.acme.repository" />

<repositories base-package="com.acme.repository" repository-impl-postfix="MyPostfix" />

Or using the @Configuration annotation :

@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {

  @Bean
  EntityManagerFactory entityManagerFactory() {
    // …
  }
}

You can load this configuration only for your 'test' profile when you are using the spring default implementation.

Best read : https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.custom-implementations

Upvotes: 2

Mike
Mike

Reputation: 5142

I think for Spring Data MongoDB, adding the @EnableMongoRepositories annotation to a @Configuration class is all you need. Just make sure it's under the same package as your main application, or configure component scan to pick it up.

Upvotes: -1

TechiRik
TechiRik

Reputation: 2133

My apologies, I had missed out on exclude criteria I had added to the Main.java class to make another profile working. @Chrylis, thanks for your pointer.

Problematic Main.java file

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class})
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

Fixed Main.java file

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class})
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

Upvotes: 0

Your interface class does not need to be annotated, as Spring Data repository interfaces are handled specially by Spring Data.

The most likely case is that your repository class isn't getting identified by Spring Data (you didn't specify a Spring Boot version or package names), in which case you may need @EnableMongoRepositories on an @Configuration class (your Spring Boot launcher class is also one of these).

Upvotes: 1

Related Questions