avro-kotlin / avro4k

Avro format support for Kotlin
Apache License 2.0
197 stars 37 forks source link

Sealed polymorphism doesn't seem to work #115

Closed acruise closed 2 years ago

acruise commented 3 years ago

Hi there, I have a sealed hierarchy that looks like this:

@Serializable
sealed abstract class Foo(val type: String)

@Serializable @SerialName("type1")
object FooType1 : Foo("type1")

@Serializable @SerialName("type2")
object FooType2 : Foo("type2")

@Serializable @SerialName("withValue")
data class FooWithValue(val value: Int) : Foo("withValue")

and I've registered them in the module like this:

polymorphic(Foo::class) {
    subclass(FooType1::class, FooType1.serializer())
    subclass(FooType2::class, FooType2.serializer())
    subclass(FooWithValue::class, FooWithValue.serializer())  
}

Now, when I try to serialize an object that contains a Foo property, I get this:

Caused by: java.util.NoSuchElementException: Collection contains no element matching the predicate.
    at com.github.avrokotlin.avro4k.encoder.UnionEncoder.beginStructure(UnionEncoder.kt:42)
    at kotlinx.serialization.internal.ObjectSerializer.serialize(ObjectSerializer.kt:23)

My versions:

thake commented 3 years ago

@acruise Thanks for raising this issue. I think the SerialName annotation is causing the problem.

thake commented 3 years ago

@acruise I tried to reproduce your issue but I wasn't successful. Can you please provide a failing unit test so that I can reproduce the issue. This was my attempt:

package com.github.avrokotlin.avro4k.io

import com.github.avrokotlin.avro4k.Avro
import io.kotest.core.spec.style.StringSpec
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic

class SerialNamePolymorphicTest : StringSpec ({
  "roundtrip without explicit registration" {
      writeRead(FooType1, Foo.serializer())
  }
    "roundtrip with explicit registration" {
        val avro = Avro(SerializersModule{
            polymorphic(Foo::class) {
                subclass(FooType1::class, FooType1.serializer())
                subclass(FooType2::class, FooType2.serializer())
                subclass(FooWithValue::class, FooWithValue.serializer())
            }
        })
        writeRead(FooType1, Foo.serializer(), avro)
    }
    "referencing foo" {
        writeRead(ReferencingFoo(FooType1), ReferencingFoo.serializer())
    }
}) {

}
@Serializable
sealed class Foo(val type: String)

@Serializable @SerialName("type1")
object FooType1 : Foo("type1")

@Serializable @SerialName("type2")
object FooType2 : Foo("type2")

@Serializable @SerialName("withValue")
data class FooWithValue(val value: Int) : Foo("withValue")

@Serializable
data class ReferencingFoo(val foo : Foo)
thake commented 2 years ago

@acruise Is this still an issue for you? I'm tending to close this issue as I'm not able to reproduce it.

acruise commented 2 years ago

@acruise Is this still an issue for you? I'm tending to close this issue as I'm not able to reproduce it.

I stopped using avro4k so I can't really help anymore, sorry!

thake commented 2 years ago

Closing as not reproducable