I have a Room @Dao with CRUD functions declared as follows:
interface IMutableDao<T> {
@RawQuery
fun syncBrokerGet(query: SupportSQLiteQuery): T?
/////////////////////////////////////////////////////////////////////////////////////////////////////
@Insert(onConflict = OnConflictStrategy.ABORT)
suspend fun insert(e: T)
@Update
suspend fun update(e: T)
@Delete
suspend fun delete(e: T)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun batchInsert(l: List<T>)
@Update
suspend fun batchUpdate(l: List<T>)
@Delete
suspend fun batchDelete(l: List<T>)
}
all other DAO classes implement this interface.
In a separate module (dynamic feature) I get a reference to the CRUD functions above, that I use to insert/update/delete records using reflection as in the following snippet:
class EntityInfoExt(val nestName: String, val localizedName: String, val clazz: KClass<out ILorikeetDbEntity>, val daoGetter: () -> IMutableDao<out ILorikeetDbEntity>) {
private var dao: IMutableDao<out ILorikeetDbEntity>? = null
private val insertRef: KFunction<*> by lazy {
dao!!::class.functions.find {it.name.equals("insert", true)}!!
}
private val deleteRef: KFunction<*> by lazy {
dao!!::class.functions.find {it.name.equals("delete", true)}!!
}
private val updateRef: KFunction<*> by lazy {
dao!!::class.functions.find {it.name.equals("update", true)}!!
}
private val getRef: KFunction<*> by lazy {
dao!!::class.functions.find { it.name.equals("syncBrokerGet", true)}!!
}
private fun validateDao() {
if (dao == null) {
dao = daoGetter()
}
}
suspend fun insert(obj: ILorikeetDbEntity) {
try {
validateDao()
insertRef.invokeSuspend(dao!!, obj)
}
catch (e: Throwable) {
if (e is InvocationTargetException) {
throw e.targetException
}
else {
throw e
}
}
}
suspend fun update(obj: ILorikeetDbEntity) {
try {
validateDao()
updateRef.invokeSuspend(dao!!, obj)
}
catch (e: Throwable) {
if (e is InvocationTargetException) {
throw e.targetException
}
else {
throw e
}
}
}
suspend fun delete(obj: ILorikeetDbEntity) {
try {
validateDao()
deleteRef.invokeSuspend(dao!!, obj)
}
catch (e: Throwable) {
if (e is InvocationTargetException) {
throw e.targetException
}
else {
throw e
}
}
}
fun getObject(id: UUID): ILorikeetDbEntity? {
try {
validateDao()
return getRef.call(dao!!, SelectObjectQuery(nestName, id).query) as? ILorikeetDbEntity?
}
catch (e: Throwable) {
if (e is InvocationTargetException) {
throw e.targetException
}
else {
throw e
}
}
}
}
The problem is that in some devices I tested on it works on others randomly the function references are not valid anymore, and I do not understand how that can happen. The following call sometimes works other it doesn't, it is like the function reference is relocated... or something like that. The call is made through a helper method because the insert/update functions are declared as suspend, the call is the following:
First I get a reference to the functions:
funInsert = dao::class.functions.find {
it.name.equals("batchInsert", true)
}!!
funUpdate = dao::class.functions.find {
it.name.equals("batchUpdate", true)
}!!
the I call the insert/update functions:
funInsert.invokeSuspend(dao, objects)
The function invokeSuspend is declared as follows:
suspend fun KFunction<*>.invokeSuspend(obj: Any, vararg args: Any?): Any? =
suspendCoroutineUninterceptedOrReturn { cont ->
call(obj, *args, cont)
}
What I cannot understand is that sometimes the call:
insert.invokeSuspend(dao, objects)
randomly throws a "method not found exception" and I really do not understand why.
Aucun commentaire:
Enregistrer un commentaire