Affects: 3.0.3

Hello everyone! I'm using Spring 3.0.3 along with Kotlin. I've notice that apparently we have a bug on dependency injection.

What I'm trying to do: Inject some dependencies by constructor. What result I'm having:

Parameter 4 of constructor in <Controller> required a bean of type <My Interface> that could not be found.

Action:

Consider defining a bean of type <My Interface> in your configuration.

The problem: I have a class that represents this interface implemented. What I've noticed: When I try to inject this class providing the generic type o List (or any Kotlin Collection), this error occurs.

Code Context: My UseCase Interface

interface UseCase<In, Out> {
    fun handle(input: In): Out
}

My UseCase implementation:

@Service
@Transactional(propagation = Propagation.REQUIRED)
class RetrieveProductHistoryUseCaseImpl(
    private val productHistoryModelRepository: ProductHistoryModelRepository,
) : UseCase<Long, List<ProductHistoryModel>> {
    @Throws(UseCaseException::class)
    override fun handle(input: Long): List<ProductHistoryModel> {
        try {
            logger.info("I=Starting search products full history, input={}", input)
            val productHistoryList = productHistoryModelRepository.retrieveByProductModelId(input)

            logger.info("I=Returning products history, productHistoryList={}", productHistoryList)
            return productHistoryList
        } catch (ex: Exception) {
            logger.error("E=It was not possible to create a new product, cause={}", ex.message, ex)
            throw UseCaseException(message = ex.message)
        }
    }

    companion object {
        private val logger: Logger = LoggerFactory.getLogger(this::class.java)
    }
}

My Controller dependency injection:

@RestController
@RequestMapping("/products")
class ProductUserController(
    private val createProductUseCaseImpl: UseCase<ProductModel, ProductModel>,
    private val retrieveProductUseCaseImpl: UseCase<Long, Optional<ProductModel>>,
    private val updateProductUseCaseImpl: UseCase<ProductModel, Optional<ProductModel>>,
    private val deleteProductUseCaseImpl: UseCase<Long, Boolean>,
    private val retrieveProductHistoryUseCaseImpl: UseCase<Long, List<ProductHistoryModel>>, // here is the problem
) {
...

If I change the second UseCase type to anything different of a Kotlin Collection at the Controller dependency injection and at my UseCase implementation, the Spring Framework start normally. But if I use any Collection, the Injection error occurs

Exemple of working case: My UseCase implementation:

...
class RetrieveProductHistoryUseCaseImpl(
    private val productHistoryModelRepository: ProductHistoryModelRepository,
) : UseCase<Long, Long> {
...

My Controller dependency injection:

@RestController
@RequestMapping("/products")
class ProductUserController(
    ...
    private val retrieveProductHistoryUseCaseImpl: UseCase<Long, Long>, // this way will work
) {
...

Exemple of not working case: My UseCase implementation:

...
class RetrieveProductHistoryUseCaseImpl(
    private val productHistoryModelRepository: ProductHistoryModelRepository,
) : UseCase<Long, List<ProductHistoryModel>> {
...

My Controller dependency injection:

@RestController
@RequestMapping("/products")
class ProductUserController(
    ...
    private val retrieveProductHistoryUseCaseImpl: UseCase<Long, List<ProductHistoryModel>>, // here is the problem
) {
...

If its is necessary, I could try to help to investigate how the dependency injection works and try to collaborate with this investigation

Comment From: camilodsilva

This is not a bug :) Once we are using generic types, we must use concrete classes as types an not an interface.

For example: Implementation of UseCase<In, Out>

...
class RetrieveProductHistoryUseCaseImpl(
    private val productHistoryModelRepository: ProductHistoryModelRepository,
) : UseCase<Long, ArrayList<ProductHistoryModel>> {
...

Constructor dependency injection
```kotlin
@RestController
@RequestMapping("/products")
class ProductUserController(
    ...
    private val retrieveProductHistoryUseCaseImpl: UseCase<Long, ArrayList<ProductHistoryModel>>, // this way works
) {
...

The example above worked fine