Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Room KMP: How to use experimental types in models?

I am trying to use Room for Kotlin Multiplatform (version 2.7.1) with ksp version 2.1.21-2.0.1.

How can I use the experimental type kotlin.time.Instant in my models?

The annotation processor apparently creates implementations without experimental annotations. This yields the error This declaration needs opt-in. Its usage must be marked with '@kotlin.time.ExperimentalTime' or '@OptIn(kotlin.time.ExperimentalTime::class)'.

I tried adding @OptIn(ExperimentalTime::class) to the member, the constructor and the data class itself, but none of those approaches seem to work. The compiler still gives the error. The compiler apparently also gives the error for accessing the type convertors even though they are annotated with @OptIn(ExperimentalTime::class) and not generated by the annotation processor. I tried putting @OptIn everywhere I can think of, but the error still persists..

Consider the following code:

@OptIn(ExperimentalTime::class)
@Database(
    version = 1,
    entities = [
        RoomEntityModel::class,
    ],
)
@TypeConverters(RoomDataConverters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun getRoomEntityDao(): RoomEntityModelDao
}

class RoomDataConverters {
    @OptIn(ExperimentalTime::class)
    @TypeConverter
    fun nullableInstantToString(value: Instant?) = value?.let { instantToString(it) }

    @OptIn(ExperimentalTime::class)
    @TypeConverter
    fun instantToString(value: Instant) = value.toString()

    @OptIn(ExperimentalTime::class)
    @TypeConverter
    fun nullableStringToInstant(value: String?) = value?.let { stringToInstant(it) }

    @OptIn(ExperimentalTime::class)
    @TypeConverter
    fun stringToInstant(value: String) = Instant.parse(value)
}

@OptIn(ExperimentalTime::class)
@Dao
interface RoomEntityModelDao : BinanceKlineModelDao {
    @OptIn(ExperimentalTime::class)
    @Insert
    suspend fun insert(vararg models: RoomEntityModel)
}

@OptIn(kotlin.time.ExperimentalTime::class)
@androidx.room.Entity("RoomEntityModel")
data class RoomEntityModel @OptIn(kotlin.time.ExperimentalTime::class) constructor(
    @androidx.room.PrimaryKey
    @androidx.room.ColumnInfo("instant")
    @OptIn(kotlin.time.ExperimentalTime::class)
    val instant: kotlin.time.Instant,
)

This results in the following implementation for RoomEntityModelDao

package REDACTED.`data`

import androidx.room.EntityInsertAdapter
import androidx.room.RoomDatabase
import androidx.room.util.performSuspending
import androidx.sqlite.SQLiteStatement
import REDACTED.`data`.local.database.RoomDataConverters
import javax.`annotation`.processing.Generated
import kotlin.String
import kotlin.Suppress
import kotlin.Unit
import kotlin.collections.List
import kotlin.reflect.KClass

@Generated(value = ["androidx.room.RoomProcessor"])
@Suppress(names = ["UNCHECKED_CAST", "DEPRECATION", "REDUNDANT_PROJECTION", "REMOVAL"])
public class RoomEntityModelDao_Impl(
  __db: RoomDatabase,
) : RoomEntityModelDao {
  private val __db: RoomDatabase

  private val __insertAdapterOfRoomEntityModel: EntityInsertAdapter<RoomEntityModel>

  private val __roomDataConverters: RoomDataConverters = RoomDataConverters()
  init {
    this.__db = __db
    this.__insertAdapterOfRoomEntityModel = object : EntityInsertAdapter<RoomEntityModel>() {
      protected override fun createQuery(): String =
          "INSERT OR ABORT INTO `RoomEntityModel` (`instant`) VALUES (?)"

      protected override fun bind(statement: SQLiteStatement, entity: RoomEntityModel) {
        val _tmp: String = __roomDataConverters.instantToString(entity.instant)
        statement.bindText(1, _tmp)
      }
    }
  }

  public override suspend fun insert(vararg models: RoomEntityModel): Unit = performSuspending(__db,
      false, true) { _connection ->
    __insertAdapterOfRoomEntityModel.insert(_connection, models)
  }

  public companion object {
    public fun getRequiredConverters(): List<KClass<*>> = emptyList()
  }
}

And gives the errors

e: file:///REDACTED/generated/ksp/jvm/jvmMain/kotlin/REDACTED/data/RoomEntityModelDao_Impl.kt:32:49 This declaration needs opt-in. Its usage must be marked with '@kotlin.time.ExperimentalTime' or '@OptIn(kotlin.time.ExperimentalTime::class)'

e: file:///REDACTED/generated/ksp/jvm/jvmMain/kotlin/REDACTED/data/RoomEntityModelDao_Impl.kt:32:72 This declaration needs opt-in. Its usage must be marked with '@kotlin.time.ExperimentalTime' or '@OptIn(kotlin.time.ExperimentalTime::class)'
like image 996
Gamer2015 Avatar asked Oct 25 '25 01:10

Gamer2015


1 Answers

I had the same problem, but with Room for Android instead of KMP.

Instead of creating wrapper classes, a cleaner solution is to opt-in to ExperimentalTime for the entire module (as suggested in this IssueTracker conversation).

To do this, add the following line to your module(app)-level build.gradle.kts file (I'm using Kotlin syntax):

// ...
android {
    // ...

    kotlin.compilerOptions.optIn.add("kotlin.time.ExperimentalTime") // <- add this line

    // ...

The following links may be helpful for adapting these configuration changes for KMP:

  • https://kotlinlang.org/docs/opt-in-requirements.html#opt-in-a-module

  • https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-dsl-reference.html#compiler-options

like image 167
David Avatar answered Oct 26 '25 18:10

David



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!