Search code examples
kotlingenericsktor

Ktor reified type parameter


I created class with generic in kotlin and want to use receive with generic, but I have error when i want to call.receive type from generic:

Can not use MType as reified type parameter. Use a class instead.

Code:

class APIRoute<EType : IntEntity, MType : Any> {
    fun Route.apiRoute() {
        post {
            val m = call.receive<MType>()
            call.respond(f(model))
        }
    }
}

How to fix it?


Solution

  • You need to provide the expected type to the receive() function. Due to type erasure in Java/Kotlin, the type of MType is unknown at runtime, so it can't be used with receive(). You need to capture the type as KType or KClass object when constructing APIRoute.

    KClass is easier to use, however it works with raw classes only, it doesn't support parameterized types. Therefore, we can use it to create e.g. APIRoute<*, String>, but not APIRoute<*, List<String>>. KType supports any type, but is a little harder to handle.

    Solution with KClass:

    fun main() {
        val route = APIRoute<IntEntity, String>(String::class)
    }
    
    class APIRoute<EType : IntEntity, MType : Any>(
        private val mClass: KClass<MType>
    ) {
        fun Route.apiRoute() {
            post {
                val m = call.receive(mClass)
                call.respond(f(model))
            }
        }
    }
    

    Solution with KType:

    fun main() {
        val route = APIRoute.create<IntEntity, List<String>>()
    }
    
    class APIRoute<EType : IntEntity, MType : Any> @PublishedApi internal constructor(
        private val mType: KType
    ) {
        companion object {
            @OptIn(ExperimentalStdlibApi::class)
            inline fun <EType : IntEntity, reified MType : Any> create(): APIRoute<EType, MType> = APIRoute(typeOf<MType>())
        }
    
        fun Route.apiRoute() {
            post {
                val m = call.receive<MType>(mType)
                call.respond(f(model))
            }
        }
    }