Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android room DAO interface does not work with inheritance

interface Marker<T : BaseFoo> {
    fun getSpecialFoo(): List<T>
}

@Dao
interface FooDao: Marker<Foo> {
    @Query("SELECT * FROM foo WHERE bar = :bar")
    fun get(bar: Int): List<Foo>

    @Transaction
    override fun getSpecialFoo(): List<Foo> {
        return get(1)
    }
}

This results in

An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery

However, Marker is not marked with @Dao and FooDao override getSpecialFoo already. Why does this error still show?

I need Marker because I need a generic DAO that has some methods. Is there a way to work around this?

The only way I can think of is marking the dao to Any and cast the type runtime or build a wrapper for the DAO.

like image 497
Joshua Avatar asked Oct 10 '18 06:10

Joshua


2 Answers

You can solve it.

The issue is not in room restrictions, but in the kotlin implementation itself. You are using generic collection method, which by default is processed to List<? extends T> java implementation, but overridden method has List<Foo> return type. Room generator matches a method signature and can't find an implemented method with the same signature, so you get

An abstract DAO method must be annotated with one and only one of the following annotations

The solution is just to annotate a method result type in the interface with @JvmSuppressWildcards:

fun getSpecialFoo(): List<@JvmSuppressWildcards T>

like image 96
Beloo Avatar answered Nov 02 '22 12:11

Beloo


This seems like it is limitation of the Room library. You can work around it like the following.

@Dao
interface FooDao {
    @Query("SELECT * FROM foo WHERE bar = :bar")
    fun get(bar: Int): List<Foo>

    @Transaction
    fun getSpecialFoo(): List<Foo> {
        return get(1)
    }
}

fun FooDao.wrapper(): Marker<Foo> {
    return Wrapper(this)
}


private class Wrapper(private val dao: FooDao): Marker<Foo> {
    override fun getSpecialFoo() = dao.getSpecialFoo()
}

When you need it to be Marker<Foo>, you can wrapper() to create a wrapper which implement Marker<Foo> by the dao.

like image 35
Joshua Avatar answered Nov 02 '22 10:11

Joshua