kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Reading deserialized generic array crashes at runtime

Open jesseschalken opened this issue 3 years ago • 0 comments

Describe the bug

The following code crashes at runtime with the error:

Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
	at MainKt.main(Main.kt:18)
	at MainKt.main(Main.kt)

To Reproduce

import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Serializable
class Blah<T>(val array: Array<T>)

@Serializable
class Foo(val blah: Blah<String>)

fun main() {
  val foo1 = Foo(blah = Blah(array = arrayOf("")))
  val foo2 = Json.decodeFromString<Foo>(Json.encodeToString(foo1))

  val array1 = foo1.blah.array
  val array2 = foo2.blah.array // <= error is here
}

Expected behavior

prints nothing (main() finishes without error)

I understand the challenge of deserializing this correctly. When Blah is deserialized, it has a KSerializer<T> but doesn't have a java.lang.Class<T> so cannot produce an accurately typed Array<T>, so produces an Array<Any?> instead which fails at runtime to cast to Array<String> (the inferred type of array2) because generic arrays on the JVM are not type-erased.

There was no IDE or compiler warning about this, nor could I find any documentation for this limitation.

Environment

  • Kotlin version: 1.6.10
  • Library version: 1.3.2
  • Kotlin platforms: JVM
  • Gradle version: 7.1
  • IDE version (if bug is related to the IDE) IntellijIDEA 2021.2.4
  • JRE 11.0.12

jesseschalken avatar Apr 25 '22 12:04 jesseschalken