I am looking for a good way to structure my Kotlin code using Spring Boot 4 and Spring 7. The new features I am using are:
- Reflectionless dependency injection via
BeanRegistrarDsl RouterFunction
I am mostly looking for a way to structure my code in a good way that is testable and at the same time, use idiomatic Kotlin. Here is my current setup, on which I am seeking review:
I have one file holding the bean wiring with several methods, each one declaring a separate BeanRegistrarDsl:
no.difi.meldingsutveksling.nhn.adapter.Beanregistration.kt
private fun properties() = BeanRegistrarDsl {
// all properties registered here
}
private fun security() = BeanRegistrarDsl {
registerBean<ReactiveUserDetailsService> { SecurityBeans.userDetailsService(bean()) }
registerBean { SecurityBeans.userDetailsRepositoryReactiveAuthenticationManager(bean<PasswordEncoder>(), bean()) }
}
// followed by one main registry wiring all submodules:
class BeanRegistration :
BeanRegistrarDsl({
this.register(properties())
this.register(security())
registerBean<RouterFunction<*>> {
coRouter {
arLookup(bean(), bean())
dphOut(bean(), bean())
statusCheck(bean())
incomingReciept(bean())
}
}
}
In no.difi.meldingsutveksling.nhn.adapter.beans.SecurityBeans.kt
I declare in an "object" all my bean initialization logic like this:
object SecurityBeans {
fun userDetailsService(passwordEncoder: PasswordEncoder): ReactiveUserDetailsService = .....
fun fun userDetailsRepositoryReactiveAuthenticationManager(
passwordEncoder: PasswordEncoder,
mapReactiveUserDetailsService: MapReactiveUserDetailsService,
)= ....
}
So I have such objects for all my other bean types.
Then I have one file with all my Routes:
fun CoRouterFunctionDsl.statusCheck(mshClient: Client) =
GET("/dph/status/{messageId}") { it -> OutHandler.statusHandler(it, mshClient) }
fun CoRouterFunctionDsl.arLookup(flrClient: DecoratingFlrClient, arClient: AdresseregisteretClient) =
GET("/arlookup/{identifier}") { ArHandlers.arLookup(it, flrClient, arClient) }
@OptIn(ExperimentalUuidApi::class)
fun CoRouterFunctionDsl.incomingReciept(mshClient: Client) =
GET("/dph/in/{messageId}/receipt") {
return@GET InHandler.incomingApprec(it, mshClient)
}
And in addition, I have a couple of files where I register my HTTP handlers like this:
object OutHandler {
suspend fun statusHandler(it: ServerRequest, mshClient: Client): ServerResponse {
........... my code here
)
}
I was considering instead of using "objects" to hold my bean initialization and handlers to use instead extension methods on: SupplierContextDsl and ServerRequest, please comment on this as approach.
I don't have experience with these two new features, and I am looking for review, validation, or rejection.