I have 2 services with request/response pattern on Kotlin Spring Boot.
In producer I tried to use generic for send method to don't write several methods with different return types:
fun <T> sendMessage(data: String) : T {
val listenableFuture = asyncRabbitTemplate.convertSendAndReceiveAsType(
directExchange.name,
"routing-key",
data,
object : ParameterizedTypeReference<T>() {}
)
return listenableFuture.get()
}
And for instance I use this method with one of Model classes:
Producer:
fun getData(): ExampleDto {
...
return rabbitTemplate.sendMessage<ExampleDto>("data")
}
Consumer:
...
@RabbitListener(...)
fun consumer(data: String): ExampleDto {
...
// processing with data
return ExampleDto(...)
}
So I get exception class java.util.LinkedHashMap cannot be cast to class com.example.model.ExampleDto (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.example.model.ExampleDto is in unnamed module of loader 'app')
If I write method without generics and declare return type directly, then everything works well. But I don't want to write dozens of methods that are different only in return type.
CodePudding user response:
Looks like ParameterizedTypeReference
is used to implement Super Type Token pattern. When you pass T
as a parameter type, the underlying logic in convertSendAndReceiveAsType
cannot infer the exact type due to generic type erasure.
You either need to parametrize your sendMessage
method with ParameterizedTypeReference
and create it with concrete type in getData()
or you can use Reified type parameters Kotlin feature to overcome this with synthetic sugar. E.g.
inline fun <reified T> sendMessage(data: String) : T {
val listenableFuture = asyncRabbitTemplate.convertSendAndReceiveAsType(
directExchange.name,
"routing-key",
data,
object : ParameterizedTypeReference<T>() {}
)
return listenableFuture.get()
}