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