Hi guys, I am facing a serialization issue when us...
# serialization
j
Hi guys, I am facing a serialization issue when using Kotlinx serialization with a Firebase Library in a KMM project. I have the following hierarchy classes that I want to persist in Firebase Realtime Databases.
Copy code
@Serializable
sealed class Activity {
  abstract val type: Type

  @Serializable
  enum class Type(
    val enabled: Boolean,
    @Transient
    val shortName: StringResource
  ) {
    BJJ(
      true,
      MR.strings.activity_bjj,
    ),
    GRAPPLING(
      true,
      MR.strings.activity_grappling,
    )
  }

  @Serializable
  data class Bjj(
    override val type: Type = Type.BJJ,
    var belt: Belt? = null,
    val stripes: Int = 0
  ) : Activity() {
    @Serializable
    enum class Belt(
      @Transient
      val color: ColorResource.Single
    ) {
      WHITE(MR.colors.belt_white),
      BLUE(MR.colors.belt_blue),
      PURPLE(MR.colors.belt_purple),
      BROWN(MR.colors.belt_brown),
      BLACK(MR.colors.belt_black)
    }
  }

  @Serializable
  data class Grappling(
    override val type: Type = Type.GRAPPLING
  ) : Activity()
}
I actually send it as a List, something like this: // Firebase Call
Copy code
val ref = database
  .child(ROOT_PATH)
  .child(user.id)
  .child("activities")
ref.setValue(ListSerializer(Activity.serializer()), updatedActivities)
Seems that the Firebase Library doesn’t support auto-serialization of sealed classes and I am not sure how to solve this problem.  
java.lang.ClassCastException: kotlinx.serialization.descriptors.PolymorphicKind$SEALED cannot be cast to kotlinx.serialization.descriptors.StructureKind
    
at dev.gitlive.firebase._encodersKt.structureEncoder(_encoders.kt:12)
so I tried defining a custom
KSerializer
for that sealed class but I still missing something
Copy code
@Serializable(with = ActivitySerializer::class)
sealed class Activity
....
Copy code
@ExperimentalSerializationApi
@Serializer(forClass = Activity::class)
object ActivitySerializer : KSerializer<Activity> {
    override val descriptor: SerialDescriptor = Activity.serializer().descriptor

    override fun serialize(encoder: Encoder, value: Activity) {
        when (value) {
            is Activity.Bjj -> encoder.encodeSerializableValue(Activity.Bjj.serializer(), value)
            is Activity.Grappling -> encoder.encodeSerializableValue(
                Activity.Grappling.serializer(),
                value
            )
        }
    }

    override fun deserialize(decoder: Decoder): Activity {
        val activity = decoder.decodeSerializableValue(Activity.serializer())
        return when (activity.type) {
            Activity.Type.BJJ -> decoder.decodeSerializableValue(Activity.Bjj.serializer())
            Activity.Type.GRAPPLING -> decoder.decodeSerializableValue(Activity.Grappling.serializer())
        }
    }
}
Using that serializer now I get:
E/UserViewModel$insertActivity$invokeSuspend: Error insertActivity
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter elementDesc
at kotlinx.serialization.internal.ArrayListClassDesc.<init>(Unknown Source:2)
at kotlinx.serialization.internal.ArrayListSerializer.<init>(CollectionSerializers.kt:208)
at kotlinx.serialization.builtins.BuiltinSerializersKt.ListSerializer(BuiltinSerializers.kt:176)
If someone has any clue would be very useful. Thanks and sorry for the long post.
n
wouldn't the type field conflict with the one the serialization tries to put in ?
j
I tried by renaming the
type
field and I got the same error, so the name shouldn’t be the problem
s
Looks like this is the issue of a particular
dev.gitlive.firebase
library, you can ask also in their tracker
👍 1