I know that Realm doesn't yet support Generics directly. I have been trying to come up with a workaround as it will reduce duplicate code immensely in my project. (I have many repos which extend base repo and a lot of functions which only differ by RealmObject extended type)
I have got a reasonably good solution working:
open class BaseRepository(private val realm: Realm) {
fun <T : RealmModel> get(ofType: Class<T>, id: Long): T? {
return realm.where(ofType).equalTo("id", id).findFirst()
}
}
This can be called by my repositories which inherit from BaseRepository like so:
customRepository.get(CustomType::class.java, id)
I tried to improve this further by passing the class type in the constructor instead of the function param:
open class BaseRepository<T : RealmModel?>(private val realm: Realm, private val ofType: Class<T>) {
fun <T : RealmModel> get(id: Long): T? {
return realm.where(ofType).equalTo("id", id).findFirst()
}
}
The above has the following compile time error:
Type mismatch.
Required: T#1 (type parameter of com.acme.data.repository.BaseRepository.get)?
Found: T#2 (type parameter of com.acme.data.repository.BaseRepository)?
I have made various attempts to get this working but as yet I am unsuccessful.
Questions:
Why can't I pass the ofType: Class in the constructor param but I can in the function param?
Does anyone know how to fix it?
Is there any issue, Realm or otherwise, with what I am doing as it does seem to work and all my tests still pass?
Has anyone got a better solution for this, for example using kotlin extension methods?
Thanks, Paul.
Actually, if you pass the class to the superclass, then you no longer need to use template parameter for your function.
open class BaseRepository<T : RealmModel>(private val realm: Realm, private val ofType: Class<T>) {
fun get(id: Long): T? =
realm.where(ofType).equalTo("id", id).findFirst()
}
An interesting tidbit is that with Kotlin, you could reduce the ::class.java
using inline <reified T>
.
open class BaseRepository(private val realm: Realm) {
inline fun <reified T : RealmModel> get(id: Long): T? =
realm.where(T::class.java).equalTo("id", id).findFirst()
}
Or if you are using a newer version of Realm (4.3.1+), then you could change this to
import io.realm.kotlin.where
open class BaseRepository(private val realm: Realm) {
inline fun <reified T : RealmModel> get(id: Long): T? =
realm.where<T>().equalTo("id", id).findFirst()
}
I'm just throwing ideas at you but you could technically make this into an extension function
inline fun <reified T : RealmModel> Realm.get(id: Long): T? =
where<T>().equalTo("id", id).findFirst()
Now you could do
val dog = realm.get<Dog>(12L)