Search code examples
javakotlingradlemicronautgradle-task

Exception in thread "main" io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter of class


I am not able to inject dependencies through Gradle task

My build.gradle

task runDataFeeder(type:JavaExec){
    classpath = sourceSets.main.runtimeClasspath
    main = "example.migrator.RunMigrator"
}

runDataFeeder class pointed to RunMigrator class

RunMigrator.kt

@Singleton
class Migrator(@Inject val pharmacySeedDataService: PharmacySeedDataService){
    fun migrate(){
        pharmacySeedDataService.createZone()
    }
}

open class RunMigrator {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            ApplicationContext.run().use { applicationContext ->
                val migrator: Migrator = applicationContext.getBean(Migrator::class.java)
                migrator.migrate()
            }
        }
    }
}

PharmacySeedDataService.kt contain

@Singleton
class PharmacySeedDataService(@Inject private val pharmacyService: PharmacyService, @Inject private val roleService: RoleService) {

    fun createZone() {
       
    }
}

And PharmacyService.kt contain

@Singleton
class PharmacyService(@Inject val pharmacyRepository: PharmacyRepository){
}

Here is PharmacyRepository.kt

@Singleton
interface PharmacyRepository {
    fun createZone(zoneName: String, locationName: String): Zone
}

But after I ran gradle task, the following exception is thrown:

Exception in thread "main" io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [pharmacyRepository] of class: delivery.core.pharmacy.PharmacyService

Message: No bean of type [delivery.core.pharmacy.PharmacyRepository] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Path Taken: new Migrator([PharmacySeedDataService pharmacySeedDataService]) --> new PharmacySeedDataService([PharmacyService pharmacyService],RoleService roleService) --> new PharmacyService([PharmacyRepository pharmacyRepository])
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1016)
    at delivery.core.pharmacy.$PharmacyServiceDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1693)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2402)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2084)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2058)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1095)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1007)
    at delivery.core.pharmacy.$PharmacySeedDataServiceDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1693)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2402)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2084)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2058)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1095)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1007)
    at delivery.core.$MigratorDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1693)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2402)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2084)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2058)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:623)
    at delivery.core.RunMigrator$Companion.main(RunMigrator.kt:20)
    at delivery.core.RunMigrator.main(RunMigrator.kt)
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [delivery.core.pharmacy.PharmacyRepository] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [delivery.core.pharmacy.PharmacyRepository] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).

Solution

  • Use an @Repository annotation to designate that PharmacyRepository is a type of a data repository that's then registered as a bean at runtime. If the type is an interface or abstract class this annotation will attempt to automatically provide implementations at compilation time.

    You can also extend the CrudRepository interface to enable automatic generation of CRUD (Create, Read, Update, Delete) operations.

    For instance:

    import io.micronaut.data.annotation.*
    import io.micronaut.data.model.*
    import io.micronaut.data.repository.CrudRepository
    
    @Repository
    interface PharmacyRepository extends CrudRepository<YOUR ENTITY HERE, YOUR ENTITY ID HERE> {
    }
    

    If you don’t want to expose all CRUD operation, for example you only allow entities to be created/updated instead of extending CrudRepository you can extend GenericRepository.

    Another option is to use a custom implementation of the PharmacyRepository to which you then add the @Repository annotation.

    import io.micronaut.data.annotation.*
    
    interface PharmacyRepository {
        fun createZone(zoneName: String, locationName: String): Zone
    }
    
    ...
    
    @Repository
    class PharmacyRepositoryImpl implements PharmacyRepository {
        // implement declared methods of the interface here
    }
    

    See 2.4 Repository Access of Micronaut Guides - Access a database with JPA and Hibernate