diff --git a/core/src/main/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumNameSerializer.scala b/core/src/main/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumNameSerializer.scala index 83b806f..1a1876b 100644 --- a/core/src/main/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumNameSerializer.scala +++ b/core/src/main/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumNameSerializer.scala @@ -11,8 +11,16 @@ class ScalaEnumNameSerializer[T <: EnumValue] extends Serializer[T] { def read(kryo: Kryo, input: Input, typ: Class[? <: T]): T = { val clazz = kryo.readClass(input).getType val name = input.readString() - // using value instead of ordinal to make serialization more stable, e.g. allowing reordering without breaking compatibility - clazz.getDeclaredMethod("valueOf", classOf[String]).invoke(null, name).asInstanceOf[T] + + try { + // using value instead of ordinal to make serialization more stable, e.g. allowing reordering without breaking compatibility + clazz.getDeclaredMethod("valueOf", classOf[String]).invoke(null, name).asInstanceOf[T] + } catch { + case _: java.lang.NoSuchMethodException => + // work around Scala 3 ADT-like enums missing valueOf method + val objectClazz = Class.forName(clazz.getName + "$") + objectClazz.getDeclaredField(name).get(null).asInstanceOf[T] + } } def write(kryo: Kryo, output: Output, obj: T): Unit = { diff --git a/core/src/test/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumSerializationTest.scala b/core/src/test/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumSerializationTest.scala index ffabf59..f1fe90f 100644 --- a/core/src/test/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumSerializationTest.scala +++ b/core/src/test/scala-3/io/altoo/serialization/kryo/scala/serializer/ScalaEnumSerializationTest.scala @@ -1,9 +1,7 @@ package io.altoo.serialization.kryo.scala.serializer import com.esotericsoftware.kryo.util.{DefaultClassResolver, ListReferenceResolver} -import io.altoo.serialization.kryo.scala.ScalaVersionSerializers -import io.altoo.serialization.kryo.scala.serializer.{ScalaEnumNameSerializer, ScalaKryo} -import io.altoo.serialization.kryo.scala.testkit.{AbstractKryoTest, KryoSerializationTesting} +import io.altoo.serialization.kryo.scala.testkit.KryoSerializationTesting import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -17,34 +15,52 @@ object ScalaEnumSerializationTest { case class EmbeddedEnum(sample: Sample) { def this() = this(null) } + + enum SimpleADT { + case A() + case B + } } -class ScalaEnumSerializationTest extends AnyFlatSpec with Matchers with KryoSerializationTesting { +class ScalaEnumSerializationTest extends AnyFlatSpec with Matchers with KryoSerializationTesting { import ScalaEnumSerializationTest.* val kryo = new ScalaKryo(new DefaultClassResolver(), new ListReferenceResolver()) kryo.setRegistrationRequired(false) kryo.addDefaultSerializer(classOf[scala.runtime.EnumValue], new ScalaEnumNameSerializer[scala.runtime.EnumValue]) - behavior of "Kryo serialization" - it should "reoundtrip enum" in { + it should "round trip enum" in { kryo.setRegistrationRequired(false) testSerializationOf(Sample.B) } - it should "reoundtrip external enum" in { + it should "round trip external enum" in { kryo.setRegistrationRequired(false) testSerializationOf(io.altoo.external.ExternalEnum.A) } - it should "reoundtrip embedded enum" in { + it should "round trip embedded enum" in { kryo.setRegistrationRequired(false) kryo.register(classOf[EmbeddedEnum], 46) testSerializationOf(EmbeddedEnum(Sample.C)) } + + it should "round trip adt enum class using generic field serializer" in { + kryo.setRegistrationRequired(false) + kryo.register(classOf[SimpleADT], 47) + + testSerializationOf(SimpleADT.A) + } + + it should "round trip adt enum object using enum serializer" in { + kryo.setRegistrationRequired(false) + kryo.register(classOf[SimpleADT], 47) + + testSerializationOf(SimpleADT.B) + } }