17
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.

1
  • 1
    @IntelliJAmiya That was a typo when I type on StackOverflow. Edited. Commented Oct 10, 2018 at 6:37

2 Answers 2

34

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>

Sign up to request clarification or add additional context in comments.

4 Comments

top best answer. i wouldn't to write a wrapper around a DAO if this is a straight and simple answer.
Tip: if your BaseDao has @Transaction annotated methods then you need to make your ConcreteClassDao not an interface, but an abstract class.
Note that if your non-Room DAO interface contains a suspend fun foos(): List<@JvmSuppressWildcards Foo>, then the generated Room DAO will show a lint error on the generated Java method: foos(Continuation<? super List<Foo>>) in com.example.FooDao_Impl clashes with foos(Continuation<? super List<? extends Foo>>) in com.example.FooDao; both methods have same erasure, yet neither overrides the other. This is likely not a problem. The Java List<E> is different from Kotlin's List<out E> (with suppressed wildcard) anyways. Please comment here, or answer if you think otherwise!
I was having headache over this. Thanks for this answer.
2

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.

1 Comment

a work around solution, but not as clean as using @JvmSuppressWildcards

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.