magnetichf
magnetichf

Reputation: 63

Parameterized interfaces in Kotlin

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

Answers (2)

magnetichf
magnetichf

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

Tenfour04
Tenfour04

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

Related Questions