I am trying to write a model object and repository that is shared between the jvm backend and the js front end. I am using ktor, kodein and kotlinx.serialization with json between the backend and the front end.
I am having trouble with generics and reified types with respect to inheritence.
Short summary: HttpClient.get<T>("url")
wants T to be a real type or it wants the type to be reified. How can I implement this in a generic (with inherited class/interface) way, or work around it?
Longer description:
I have a BaseRepository that looks like this:
interface BaseRepository<T: WithIdAndVersion> {
/**
* Finds the object given by the id and returns it. If it is not found, null is returned.
*/
suspend fun find(id: Long): T?
etc
I then have a RemoteRepository on the js side and a DbRepository on the jvm side. The RemoteRepository one looks like:
open class RemoteRepository<T: WithIdAndVersion>(val classUrl: String) : BaseRepository<T> {
@Suppress("OVERRIDE_BY_INLINE")
final override suspend inline fun <reified T> find(id: Long): T? {
HttpClient(Js) {
install(JsonFeature) {
serializer = defaultSerializer()
}
}.use {
return try {
it.get<T>("$baseUrl/$id")
} catch(e: BadResponseStatusException) {
if (e.statusCode == HttpStatusCode.NotFound) {
null
} else {
throw e
}
}
}
}
etc
This doesn’t compile because the find function in the base interface is not reified, and it is not allowed to be because reified needs the function to be inlined and inlined can’t be on virtual methods. (If I call it find2, i.e. not override it, it works, but I am using Kodein for injection so implementing the base interface is important)
How I got to all the reifiing, inlining, etc in the first place was because of the HttpClient.get<T>("url")
. It wants a real type or it wants the type to be reified.
So how can I create a generic find function as above, or work around the HttpClient.get and get a real kotlin type back (rather than a pseudo javascript JSON created class).
Not sure how best to proceed… any pointers appreciated.