Hello,
as I’ve read countless threads on here and stackoverflow it is not possible to have a reified T at class level as
class MyClass<reified T>()
But I am creating a class that is a generic base implementation for a websocket onMessage function that should take in a string and parse it into the Generic U before using it to do some routing.
for this I need to be able to provide a generic U of the type Message, but the code bellow doesn’t work as the function ‘validateMessage’ T to be reified, which isn’t possible with U at a class level.
Any idea about how to solve this problem?
open class WebSocket<out U: Message>(private val broadcaster: WebSocketBroadcaster) {
open fun onMessage(
message: String,
session: WebSocketSession?
): Publisher<Message>? {
val result = validateMessage<U>(message)
val clientMessage: U = result.getOrElse {
val newMessage = GameServerMessage(
action = ServerAction.ERROR,
text = "Invalid Message"
)
return session?.send(newMessage)
}
return route(clientMessage, session)
}
private fun route(message: Message, session: WebSocketSession?): Publisher<Message>? {
for (function in this::class.declaredMemberFunctions) {
val isOnActionFunction = function.annotations.any { it -> it is OnAction }
if (isOnActionFunction) {
for (par in function.parameters) {
println(par)
}
function.call(this, message, session)
}
}
val newMessage = GameServerMessage(
action = ServerAction.ERROR,
text = "Invalid Message"
)
return session?.send(newMessage)
}
private inline fun <reified T> validateMessage(message: String): Result<T> {
return try {
val messageObject = Klaxon().parse<T>(message)
messageObject?.let {
return Result.success(it)
}
Result.failure<T>(NullPointerException())
} catch(e: KlaxonException) {
Result.failure<T>(e)
} catch(e: IllegalArgumentException) {
Result.failure<T>(e)
}
}
}
Error from code: Cannot use 'U' as reified type parameter. Use a class instead.
As the error says: Use a class instead. Add to your class’s primary constructor a property of type Class<U>, and use that to do the necessary casting &c. (You’ll probably find that the compiler will then infer U without you needing to specify that too.)
This isn’t an ideal approach — it’s awkward, and some types don’t correspond directly to classes (nullable types being the most obvious) — but I think it’s fairly common.
Thank you for the snippet. However, I don’t think this works for my case, or I might just not understand how to properly use it.
As far as i understand that snippet basically just autofills the type argument with T when creating a new Test object, instead of just writing Test(String::class)?
Trying to implement it I still get that Cannot use 'U' as reified type parameter. Use a class instead. which stems from this line
val result = validateMessage<U>(message)
trying to replace U with ‘type’, ‘this’, ‘WebSocket’ etc. doesn’t work.