3

I'm working on a Kotlin Multi-platform project and got a problem of saving database entity object. when I call insert method of my sqldelight dao classes exception where thrown

kotlinx.serialization.SerializationException: Serializer for class 'UnitEntity' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
    at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
    at kotlinx.serialization.internal.PlatformKt.platformSpecificSerializerNotRegistered(Platform.kt:29)
    at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:59)
    at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
.....

That example class is generated entity class

import com.example.package.core.entity.UnitEntity;
import com.example.package.core.entity.ResourceTypeEntity;

CREATE TABLE IF NOT EXISTS `ResourceEntity` (
`id` TEXT NOT NULL,
`name` TEXT NOT NULL,
`unitEntity` TEXT AS UnitEntity NOT NULL,
`type` TEXT AS ResourceTypeEntity NOT NULL,
PRIMARY KEY(`id`));

CREATE TABLE IF NOT EXISTS `ResourceTypeEntity` (
`typeId` TEXT NOT NULL,
`typeName` TEXT NOT NULL,
PRIMARY KEY(`typeId`)
);

CREATE TABLE IF NOT EXISTS `UnitEntity` (`unitId` TEXT NOT NULL, `unitName` TEXT NOT NULL, PRIMARY KEY(`unitId`));


save:
INSERT OR REPLACE INTO ResourceEntity
VALUES ?;

And here is the DAO class:

 class ResourcesDaoImpl(private val dao: Resources_daoQueries) : ResourcesDao {
  override suspend fun save(resources: List<ResourceEntity>) {
    resources.forEach {
      dao.save(it)
    }
  }
}

when I try to call that save method it crashes and says to mark that class as @Serializable and I don't understand why it says that because it is a generated class and I can't modify those classes.

Here is a snippet how I'm trying to save those entities

val mappedData = itemsDto.map {
    ResourceEntity(
      id = it._id,
      name = it.name,
      type = ResourceTypeEntity(typeId = it.type._id, typeName = it.type.name),
      unitEntity = UnitEntity(unitId = it.unit._id, unitName = it.unit.unit)
    )
  }
resourcesDao.save(mappedData)

libraries:

val coroutinesVersion = "1.3.9-native-mt"
val ktor_version = "1.4.2"
val serializationVersion = "1.0.0-RC"
val koin_version = "3.0.0-alpha-4"
val sqlDelight = "1.4.4"

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
implementation("com.squareup.sqldelight:runtime:$sqlDelight")
// SqlDelight extension
implementation("com.squareup.sqldelight:coroutines-extensions:$sqlDelight")

And here is the actual entities and save method which is generated by SqlDelight

data class ResourceTypeEntity(
  val typeId: String,
  val typeName: String
) {
  override fun toString(): String = """
  |ResourceTypeEntity [
  |  typeId: $typeId
  |  typeName: $typeName
  |]
  """.trimMargin()
}

RecourceEntity.class

import com.squareup.sqldelight.ColumnAdapter

data class ResourceEntity(
  val id: String,
  val name: String,
  val unitEntity: UnitEntity,
  val type: ResourceTypeEntity
) {
  override fun toString(): String = """
  |ResourceEntity [
  |  id: $id
  |  name: $name
  |  unitEntity: $unitEntity
  |  type: $type
  |]
  """.trimMargin()

  class Adapter(
    val unitEntityAdapter: ColumnAdapter<UnitEntity, String>,
    val typeAdapter: ColumnAdapter<ResourceTypeEntity, String>
  )
}

UnitEntity.class

data class UnitEntity(
  val unitId: String,
  val unitName: String
) {
  override fun toString(): String = """
  |UnitEntity [
  |  unitId: $unitId
  |  unitName: $unitName
  |]
  """.trimMargin()
}

Save method

  override fun save(ResourceEntity: ResourceEntity) {
    driver.execute(-1658323214, """
     |INSERT OR REPLACE INTO ResourceEntity
     |VALUES (?, ?, ?, ?)
       """.trimMargin(), 7) {
          bindString(1, ResourceEntity.id)
          bindString(2, ResourceEntity.name)
          bindString(3,
          database.ResourceEntityAdapter.unitEntityAdapter.encode(ResourceEntity.unitEntity))
      bindString(4, database.ResourceEntityAdapter.typeAdapter.encode(ResourceEntity.type))
    }
    notifyQueries(-1658323214, {database.resources_daoQueries.getResources +
        database.resources_daoQueries.getResourceByManufacturerId})
  }
Jemo Mgebrishvili
  • 5,187
  • 7
  • 38
  • 63

1 Answers1

0

You can add the annotation to ResourceEntity: add a @Serializable(with = UnitEntitySerializer::class) above the UnitEntity field.

Then you need to define UnitEntitySerializer to actually help serialize it. This is what I did with UUID in my question/ answer. However, I'm not sure what UnitEntity so I can't help you serialize it/ write UnitEntitySerializer

Ben Butterworth
  • 22,056
  • 10
  • 114
  • 167
  • I can't add that annotation on top of those entities because it is auto generated clases – Jemo Mgebrishvili Dec 22 '20 at 11:36
  • "those entities"? You only need to modify `ResourceEntity`. You don't modify `UnitEntity`, but `above the UnitEntity field` in `ResourceEntity`. Do you mean `ResourceEntity` is also generated? In that case, I'd have to go back to https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md – Ben Butterworth Dec 22 '20 at 11:41
  • Specifically, have a look here: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#serializing-3rd-party-classes – Ben Butterworth Dec 22 '20 at 11:43
  • Yes it is also generated, I just added that classes to my question. I'll explore in more details thanks. – Jemo Mgebrishvili Dec 22 '20 at 11:47