Status Update
Comments
yb...@google.com <yb...@google.com> #2
For Kotlin 2.0 and KSP 2.0 the Cannot change attributes of configuration ':composeApp:debugFrameworkIosX64' after it has been locked for mutation
really seems like a KSP issue. You should file a bug in their repository with a sample app if possible.
If you downgrade to Kotlin 1.9 then things 'should' work, there are example apps out there with such configuration, like the following one:
st...@gmail.com <st...@gmail.com> #3
Will try to use the example provided by you to check if it fixes the issue.
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #4
Note that this issue happens when applying the Compose, KSP and Room Plugin together in Kotlin 2.0.x, the workaround for now is to not use the Room Gradle Plugin and instead specify the schema location vis KSP arguments:
// In the build.gradle
ksp {
arg("room.schemaLocation", "${projectDir}/schemas")
}
el...@google.com <el...@google.com>
ap...@google.com <ap...@google.com> #5
Hi, I encountered a similar problem and was able to resolve it by updating the dependencies
room = "2.7.0-alpha08"
ksp = "2.0.20-1.0.25"
compose-plugin = "1.6.11"
kotlin = "2.0.20"
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)
.