Status Update
Comments
yb...@google.com <yb...@google.com> #2
Hi. Thanks for reporting this. Fixed in alpha-04
st...@gmail.com <st...@gmail.com> #3
Branch: androidx-main
commit e782987543a9f8ccd485e970ddc74564b24378db
Author: Vighnesh Raut <vighnesh.raut13@gmail.com>
Date: Mon Jan 02 15:27:40 2023
fix: tab row crashes when only 1 tab is added
Bug:
Test: Added unit test
Change-Id: I6381dbac304fc1d69d3708c6655f8b595668e93f
M tv/tv-material/src/androidTest/java/androidx/tv/material/TabRowTest.kt
M tv/tv-material/src/main/java/androidx/tv/material/TabRow.kt
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #4
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #5
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.tv:tv-material:1.0.0-alpha04
ph...@gmail.com <ph...@gmail.com> #6
The fix doesn't work for a case where the generic type parameter is only used as a parameter to another generic type. I'm using the roomerror.zip from the opening post, with only these two modifications:
interface BaseDao<Key, Value> {
fun getItem(id: Key): Value?
fun delete(id: Collection<Key>) // Previously: fun delete(id: Key)
}
@Dao
interface FooDao: BaseDao<Long, Foo> {
@Query("select * from foo where id=:id")
override fun getItem(id: Long): Foo?
@Query("delete from foo where id IN (:id)") // Previously: @Query("delete from foo where id=:id")
override fun delete(id: Collection<Long>) // Previously: override fun delete(id: Long)
}
Note that if it weren't for the super interface, the delete function accepting Collection<Long>
would be treated perfectly fine by Room. But now it complains:
roomerror/app/build/tmp/kapt3/stubs/debug/com/roomerror/BaseDao.java:11: error: An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery
public abstract void delete(@org.jetbrains.annotations.NotNull()
^
I imagine this happens because of some type erasure. For the same reason, it's incredibly difficult for me to work around this issue. If I use a signature with vararg id: Key
instead, Room is happy, but I can't call the function anymore. That's because my call site looks sth like this:
class Manager<Key, Value> {
private val dao: BaseDao<Key, Value>
private val stuff: List<Key>
fun clear() { dao.delete(*stuff.toTypedArray()) } // It seems impossible to convert stuff to vararg when Key is not reified.
}
ph...@gmail.com <ph...@gmail.com> #7
Just realized it might be cleaner to file this as a new bug, as it's not specific to primitives and rather it's specific to type erasure.
ph...@gmail.com <ph...@gmail.com> #8
I believe this test case for room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
might reproduce the underlying problem:
@Test
fun overrideMethodWithGenericTypeArgument() {
val src = Source.kotlin(
"ParentWithGenericTypeArgument.kt",
"""
interface ParentWithGenericTypeArgument: GenericInterface<String> {
override fun child(arg: Collection<String>)
}
interface GenericInterface<T> {
fun child(arg: Collection<T>)
}
""".trimIndent()
)
runProcessorTest(sources = listOf(src)) { invocation ->
val objectMethodNames = invocation.processingEnv.requireTypeElement(Any::class)
.getAllMethods().jvmNames()
fun XMethodElement.signature(
owner: XType
): String {
val methodType = this.asMemberOf(owner)
val params = methodType.parameterTypes.joinToString(",") {
it.typeName.toString()
}
return "$jvmName($params):${returnType.typeName}"
}
fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot {
it.jvmName in objectMethodNames
}.map { it.signature(this.type) }.toList()
invocation.processingEnv.requireTypeElement(
"ParentWithGenericTypeArgument"
).let { parent ->
assertWithMessage(parent.qualifiedName).that(
parent.allMethodSignatures()
).containsExactly(
"child(java.util.Collection<java.lang.String>):void"
)
}
}
}
In particular, room-compiler
fails to recognize that child(arg: Collection<String>)
overrides child(arg: Collection<T>)
. Kotlin clearly thinks that it does override, as it doesn't complain about the override
keyword.
ph...@gmail.com <ph...@gmail.com> #9
This problem happens because fun child(arg: Collection<T>)
is converted to void child(@NonNull Collection<? extends T>)
in Java, because Kotlin declares a covariant type parameter Collection<out T>
. This isn't the case for MutableCollection
, so using that instead make things work, though I consider that an ugly workaround.
Description
Component used:
Compiler
Version used:
2.2.4
Devices/Android versions reproduced on:
Any
Consider we have an interface in Kotlin:
And the implementation:
Compiling this yields:
An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery public abstract Value getItem(Key id);
This is due to the Kotlin way of handling its primitives and even though the
Key
type will be set correctly tojava.lang.Long
but the method signature will begetItem(long id)
.