Reputation: 63
I'm building a Kotlin microservice that processes events of various types and publishes them out to external partner systems. I have all of the event classes implementing a common interface called GenericPartnerEvent
:
interface GenericPartnerEvent
data class EventTypeOne(
val key: String,
val payload: String
) : GenericPartnerEvent
I then have a series of event handler classes, one per external partner, that are defined like this:
interface PartnerEventHandler<in T : GenericPartnerEvent> {
fun handleEvent(event: T)
}
class PartnerOneEventTypeOneHandler : PartnerEventHandler<EventTypeOne> {
...
}
I want a generic way to fetch the event handler class of the correct type given a partner and event type; something like:
fun getEventHandler(partner: String, eventType: String): PartnerEventHandler<GenericPartnerEvent> {
if (...something...) return PartnerOneEventTypeOneHandler()
}
But what I inevitably get is something like:
Type mismatch.
Required: PartnerEventHandler<GenericPartnerEvent>
Found: PartnerOneEventTypeOneHandler
Is there a way to do this?
Upvotes: 1
Views: 94
Reputation: 63
FWIW, this approach seems to pass muster with the compiler:
inline fun <reified T : GenericPartnerEvent> getHandlerForPartner(partner: String): PartnerEventHandler<T>? {
return when (partner) {
"partner-one" -> when (T::class) {
EventTypeOne::class -> PartnerOneEventTypeOneHandler() as PartnerEventHandler<T>
EventTypeTwo::class -> PartnerOneEventTypeTwoHandler() as PartnerEventHandler<T>
else -> null
}
"partner-two" -> when (T::class) {
EventTypeOne::class -> PartnerTwoEventTypeOneHandler() as PartnerEventHandler<T>
EventTypeTwo::class -> PartnerTwoEventTypeTwoHandler() as PartnerEventHandler<T>
else -> null
}
else -> null
}
}
It does give me a warning: Unchecked cast: PartnerOneEventTypeOneHandler to PartnerEventHandler<T>
. So I guess we'll see what happens at runtime.
Upvotes: 1
Reputation: 93571
No, since your PartnerEventHandler type is contravariant (in
), a subtype's type cannot be upcast. A PartnerEventHandler<EventTypeOne>
cannot accept any subtype of GenericPartnerEvent
as an input, so a PartnerEventHandler<EventTypeOne>
is not a subtype of PartnerEventHandler<GenericPartnerEvent>
.
Since you retrieve handlers using a String representation of the type, I don't see how generics buy you anything here anyway. The handle
function might as well take an input type of Any and reject incorrect types with an exception or by returning null or something.
Upvotes: 1