'kotlin sealed class with Spring @Component
I am relatively new to kotlin but already loving it. In one of our projects, we use kotlin; when I tried to annotate a sealed class with Spring's @Component, the compiler threw the following exception,
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ShutDownManager' available
The simple shutdown manager class
package com.tes.streamconsumer.stream.processor
@Component
sealed class ShutDownManager(
@Autowired private val applicationContext: ApplicationContext
) {
fun shutDownApplication() {
SpringApplication.exit(applicationContext)
}
}
That is Autowired in another class,
package com.tes.streamconsumer.stream.processor
@Component
class AccountFacade(
@Autowired private val shutDownManager: ShutDownManager
) {
}
From the Kotlin documentation on sealed class, I understand this is useful to have restricted class hierarchies that provide more control over inheritance, so my questions below,
- Is the sealed class not meant to be used with spring injection
- or the ApplicationContext not ready hence the bean was not created?
Please shed light on what I miss here; thanks.
Solution 1:[1]
Your problem is nothing to do with the sealed class but elsewhere. Typically this kind of error occurs because Spring is not scanning your code looking for Beans in the way you expect.
You have correctly annotated your ShutDownManager class with @Component but you don't give enough information on your package structure.
This is the right kind of package structure for a Spring project:
com.mydomain.myapp
.facades
.AccountFacade.kt
.managers
.ShutDownManager.kt
.MyApp.kt
What is important is the Spring entrypoint class is higher than all the packages where you declare your Beans. The default behaviour of Spring is to Scan the packages below looking for Components/Services/etc. (You can override the behaviour to scan packages, etc explicitly, but my general preference is to locate the entry point for your application at the top of the tree on its own so it is easy to find in the tree structure and then everything beneath.)
One other word of caution is that in Java the package structure is intrinsically linked to the file system folder structure - you must keep them matched. There is no such restriction in Kotlin. I recommend not making use of this, since many Java devs will use the folder structure and never notice the package declaration differs; this could also be the source of Spring not finding your Beans.
Use of sealed classes/interfaces
I guess you might be thinking of using sealed to protect your ShutDownManager from being subclassed or overriden, but actually by default Kotlin makes all classes final. (You have to explicitly permit subclassing using the open keyword.)
sealed classes have some specific benefits in other places - most often when you are creating data objects, say Apple and Pear that implement/extend from Fruit. You can then write code that knows that there can only be two fruits if you had said sealed class Fruit. In Kotlin there is a when statement that's like Java's switch...case, and the compiler would know there is no need for an else if you were using a sealed Fruit class. See this article:
https://commonsware.com/Kotlin/pages/chap-sealed-002.html
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | AndrewL |
