google / ksp

Kotlin Symbol Processing API
https://github.com/google/ksp
Apache License 2.0
2.87k stars 272 forks source link

[ksp] java.lang.IllegalArgumentException: List has more than one element. #1700

Open mtrakal opened 9 months ago

mtrakal commented 9 months ago
> Task :common:kspDevDebugKotlin FAILED
e: [ksp] java.lang.IllegalArgumentException: List has more than one element.
        at kotlin.collections.CollectionsKt___CollectionsKt.single(_Collections.kt:610)
        at androidx.room.ext.Xelement_extKt.getValueClassUnderlyingProperty(xelement_ext.kt:35)
        at androidx.room.solver.TypeAdapterStore.createDefaultTypeAdapter(TypeAdapterStore.kt:383)
        at androidx.room.solver.TypeAdapterStore.findColumnTypeAdapter(TypeAdapterStore.kt:368)
        at androidx.room.processor.FieldProcessor.process(FieldProcessor.kt:63)
        at androidx.room.processor.PojoProcessor.doProcess(PojoProcessor.kt:173)
        at androidx.room.processor.PojoProcessor.access$doProcess(PojoProcessor.kt:56)
        at androidx.room.processor.PojoProcessor$process$1.invoke(PojoProcessor.kt:112)
        at androidx.room.processor.PojoProcessor$process$1.invoke(PojoProcessor.kt:109)
        at androidx.room.processor.cache.Cache$Bucket.get(Cache.kt:53)
        at androidx.room.processor.PojoProcessor.process(PojoProcessor.kt:109)
        at androidx.room.processor.TableEntityProcessor.doProcess(TableEntityProcessor.kt:93)
        at androidx.room.processor.TableEntityProcessor.access$doProcess(TableEntityProcessor.kt:44)
        at androidx.room.processor.TableEntityProcessor$process$1.invoke(TableEntityProcessor.kt:53)
        at androidx.room.processor.TableEntityProcessor$process$1.invoke(TableEntityProcessor.kt:52)
        at androidx.room.processor.cache.Cache$Bucket.get(Cache.kt:53)
        at androidx.room.processor.TableEntityProcessor.process(TableEntityProcessor.kt:52)
        at androidx.room.processor.DatabaseProcessor.processEntities(DatabaseProcessor.kt:468)
        at androidx.room.processor.DatabaseProcessor.doProcess(DatabaseProcessor.kt:69)
        at androidx.room.processor.DatabaseProcessor.process(DatabaseProcessor.kt:60)
        at androidx.room.DatabaseProcessingStep$process$databases$1$1.invoke(DatabaseProcessingStep.kt:68)
        at androidx.room.DatabaseProcessingStep$process$databases$1$1.invoke(DatabaseProcessingStep.kt:64)
        at androidx.room.processor.Context.collectLogs(Context.kt:192)
        at androidx.room.DatabaseProcessingStep.process(DatabaseProcessingStep.kt:64)
        at androidx.room.compiler.processing.CommonProcessorDelegate.processRound(XBasicAnnotationProcessor.kt:130)
        at androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor.process(KspBasicAnnotationProcessor.kt:62)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$8$1.invoke(KotlinSymbolProcessingExtension.kt:305)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$8$1.invoke(KotlinSymbolProcessingExtension.kt:303)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:409)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:303)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:88)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:256)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:42)
        at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:115)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:247)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:87)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:47)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:168)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:53)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:100)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:46)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1497)
        at jdk.internal.reflect.GeneratedMethodAccessor43.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
        at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:840)

e: Error occurred in KSP, check log for detail

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':common:kspDevDebugKotlin'.

Why did this happen? Because we use value class which is stored to room.

    ksp {
        arg("room.schemaLocation", "$projectDir/schemas")
        arg("room.generateKotlin", "true")
    }
@Dao
interface RentalDao {

    @Query("SELECT * FROM RentalEntity ORDER BY dateFrom ASC")
    fun getRentalsFlow(): Flow<List<RentalEntity>>

    @Query("SELECT * FROM RentalEntity WHERE id = :rentalId LIMIT 1")
    fun getRentalFlow(rentalId: String): Flow<RentalEntity?>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(rental: RentalEntity)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertAll(list: List<RentalEntity>)

    @Query("SELECT * FROM RentalEntity WHERE state IN (:queryList)")
    fun pagingSource(queryList: List<String>): PagingSource<Int, RentalEntity>

    @Query("DELETE FROM RentalEntity")
    suspend fun deleteAll()

    @Query("DELETE FROM RentalEntity WHERE state IN (:stateList)")
    suspend fun deleteByState(stateList: List<String>)
}
@Entity
data class RentalEntity(
    @PrimaryKey
    val id: String,
    val totalAmount: Amount?,
)
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.math.BigDecimal

@Parcelize
@JvmInline
value class Amount(
    val value: BigDecimal,
) : Parcelable {
    companion object {

        @Throws(IllegalArgumentException::class)
        operator fun invoke(amount: Float?): Amount {
            requireNotNull(amount) { "Amount cannot be null!" }
            return Amount(amount.toBigDecimal())
        }

        private const val AMOUNT_MOVE_POINT_BY = 2 // FIXME!!! This line caused this `[ksp] java.lang.IllegalArgumentException: List has more than one element.` crash
    }
}

versions tested:

kotlin = "1.9.10"
room = "2.6.1"
kspPlugin = "1.9.10-1.0.13"

and

kotlin = "1.9.22"
kspPlugin = "1.9.22-1.0.17"
room = "2.6.1"

The private const val AMOUNT_MOVE_POINT_BY = 2 cause, that KSP failed with a weird error. When line is commented or removed, app/KSP build is a success.

Having another funs in companion object is not problem. Only val is. private val AMOUNT_MOVE_POINT_BY = 2 is not OK as well.

Move variable on top (before functions) but still in companion object causes the same problem (so not relevant to ordering).

mtrakal commented 9 months ago

it happens only in some build cases, but 100% reproducible while run ./gradlew clean assembleDebug --no-build-cache --no-daemon

mauam1 commented 9 months ago

Configuring room to generate kotlin seems to fix this issue for me.

android { ... ksp { arg("room.generateKotlin", "true") } }

edit: sorry I missed that the author had this already enabled.

dant3 commented 9 months ago

Configuring room to generate kotlin seems to fix this issue for me.

android { ... ksp { arg("room.generateKotlin", "true") } }

It does not, and in fact the author of the issue have this option enabled too.

dant3 commented 9 months ago

I have exactly the same issue and can confirm it's not 100% reproducible. I was using value class just fine in my Room code, but at some point in time suddently I started to get this error. Calling build with ./gradlew clean assembleDebug --no-build-cache --no-daemon sometimes allows the issue to go away, but most of the times it does not. FWIW I have a

kotlin = "1.9.22"
kspPlugin = "1.9.22-1.0.17"
room = "2.6.1"

and in my build I have

    ksp {
        arg("room.generateKotlin", "true")
    }
dant3 commented 9 months ago

Writing a converter for your value type resolves the issues.

@JvmInline
value class ArticleId(val id: String)

class IdConverter {
    @TypeConverter
    fun toArticleId(value: String?): ArticleId? = value?.let(::ArticleId)

    @TypeConverter
    fun toString(value: ArticleId?): String? = value?.id
}
Kodemikkel commented 8 months ago

I'm getting the same compilation error myself. I haven't yet been able to figure out what part of my code is causing it, and there seem to be no working answers when searching for it.

kotlin = "1.9.22"
kspPlugin = "1.9.22-1.0.17"
room = "2.6.1"

Edit: Turns out this was caused by me trying to save a LocalTime object to the database, which I had implemented a type converter for, but I had accidentally added the type converters to my DAO and not my database class... After changing that, the issue was resolved :)

Leojangh commented 8 months ago

My situation was very similar to yours, it was fixed when I moved the const out of the value class. For you, you can try moving private const val AMOUNT_MOVE_POINT_BY = 2 // FIXME!!! out, as a top level const.

mtrakal commented 8 months ago

@Leojangh we have, of course, moved it outside of value class to some Constants class. As I described in first comment, I know what exactly caused the issue and how to workaroundi it :), but it's still the valid KSP issue.

We don't use top level constants if it's not needed (and I don't see any reason have specific constant as global/top level) :)

Xertrec commented 5 months ago

Configuring room to generate kotlin seems to fix this issue for me.

android { ... ksp { arg("room.generateKotlin", "true") } }

edit: sorry I missed that the author had this already enabled.

me too, but to the author no, he said it in the post

nusilveira commented 5 months ago

@Leojangh we have, of course, moved it outside of value class to some Constants class. As I described in first comment, I know what exactly caused the issue and how to workaroundi it :), but it's still the valid KSP issue.

We don't use top level constants if it's not needed (and I don't see any reason have specific constant as global/top level) :)

What about native value classes like kotlin.time.Duration? I can't do that and facing the OP issue

mdsabbir48 commented 4 months ago

room database don't store float type data