简体   繁体   中英

Autowiring Generic in Spring Boot / Kotlin

currently I have classes like the follwing:

interface Mapper<IN, OUT> {
    fun map(input: IN): OUT
}

@Service
class ContractPhaseMapper: Mapper<Contract, List<ContractPhase>> {
    override fun map(input: Contract): List<ContractPhase> = contract.phases.map { 
        ContractPhase(...)
    }
}

@Service
class ContractPhaseProcessor(private val contractPhaseMapper: Mapper<Contract, List<ContractPhase>>) {
    fun createResponse(contracts: List<Contract>) = SomeResponse(
        contractPhases = contracts.map { contractPhaseMapper.map(it) }.flatten()
    )
}

Unfortunately this causes Spring to bail out with the message:

Parameter # of constructor in my.package.ContractPhaseProcessor required a bean of type 'my.package.mapper.Mapper' that could not be found.

It works fine if I try a Mapper like Mapper<Contract, Customer> though.

I also tried using @Qualifier to make it explict to use this service, but it still does not work.

Does anybody know of a simple solution to this problem?

I can't figure out exactly why your approach does not work - but I have reproduced your problem and can suggest you a workaround: if you configure your Spring beans using a @Condiguration annotated class instead of your @Service annotations, all works fine:

class ContractPhaseMapper: Mapper<Contract, List<ContractPhase>> {
    override fun map(input: Contract): List<ContractPhase> = ...
}

class ContractPhaseProcessor(private val contractPhaseMapper: Mapper<Contract, List<ContractPhase>>) {
    fun createResponse(contracts: List<Contract>) : String = ...
}

@Configuration
open class MyConfiguration {
    @Bean
    open fun mapper() : Mapper<Contract, List<ContractPhase>> = ContractPhaseMapper()

    @Bean
    open fun processor(mapper: Mapper<Contract, List<ContractPhase>>) : ContractPhaseProcessor = ContractPhaseProcessor(mapper)
}

// Main function, that wires up the application context deriving bean definitions
//  from the given class MyConfiguration, annotated with @Configuration
fun main() {
   AnnotationConfigApplicationContext(MyConfiguration::class.java).use { context ->
        val component = context.getBean(ContractPhaseProcessor::class.java)
        println(component)
        println(component.createResponse(listOf()))
    }
}

I hope this can help you to work around your problem!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM