After upgrading the service from Scala 2.12 to Scala 2.13, we encountered an issue where the service fails to read existing binary data from disk, resulting in deserialization exceptions. The binary data is of type Array[Byte]
, and the problem appears to stem from changes in Scala’s internal collection implementations. We are using the Twitter Chill library (which is built on top of Kryo) for binary serialization and deserialization. Has anyone else experienced similar issues, or is there a recommended approach to resolve this incompatibility?
Exception:
aggregated state deserialization failure java.lang.IndexOutOfBoundsException: Index 103 out of bounds for length 4
Example:
// Scala 2.13
import com.twitter.chill.{KryoPool, ScalaKryoInstantiator}
val kryoPool: KryoPool = KryoPool.withByteArrayOutputStream(30, new ScalaKryoInstantiator())
val data = Map("string-key" -> Map("inner-key" -> "this value will convert to array of bytes".getBytes))
val data: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Array[Byte]]] = Map(string-key -> Map(inner-key -> Array(116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)))
kryoPool.toBytesWithoutClass(data)
val res0: Array[Byte] = Array(1, 1, 39, 1, 3, 1, 115, 116, 114, 105, 110, 103, 45, 107, 101, -7, 26, 1, 1, 39, 1, 3, 1, 105, 110, 110, 101, 114, 45, 107, 101, -7, 96, 1, 42, 116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)
kryoPool.fromBytes(res0, classOf[Map[String, Map[String, Array[Byte]]]])
val res1: Map[String,Map[String,Array[Byte]]] = Map(string-key -> Map(inner-key -> Array(116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)))
// Scala 2.12
import com.twitter.chill.{KryoPool, ScalaKryoInstantiator}
val kryoPool: KryoPool = KryoPool.withByteArrayOutputStream(30, new ScalaKryoInstantiator())
val data = Map("string-key" -> Map("inner-key" -> "this value will convert to array of bytes".getBytes))
data: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Array[Byte]]] = Map(string-key -> Map(inner-key -> Array(116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)))
kryoPool.toBytesWithoutClass(data)
res0: Array[Byte] = Array(1, 1, 39, 1, 3, 1, 115, 116, 114, 105, 110, 103, 45, 107, 101, -7, 26, 1, 1, 39, 1, 3, 1, 105, 110, 110, 101, 114, 45, 107, 101, -7, 95, 1, 42, 116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)
kryoPool.fromBytes(res0, classOf[Map[String, Map[String, Array[Byte]]]])
res1: Map[String,Map[String,Array[Byte]]] = Map(string-key -> Map(inner-key -> Array(116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 105, 108, 108, 32, 99, 111, 110, 118, 101, 114, 116, 32, 116, 111, 32, 97, 114, 114, 97, 121, 32, 111, 102, 32, 98, 121, 116, 101, 115)))
Difference:
Is there a way to ensure compatibility with existing data after upgrading to Scala 2.13?