In my project I'm working with various handlers to perform logic on arrays of different primitive types, and I came across this runtime error:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
In this case I was working with Bytes, hence the [B, but one of my functions returned [Ljava.lang.Object instead (at runtime!). How can I ensure my generic functions return primitive arrays instead of object arrays?
Here's a minimal example to reproduce it:
package asdf
import scala.reflect.ClassTag
import java.nio.charset.StandardCharsets
object Main {
trait Helper[A, B] {
def decode(bytes: Array[Byte]): Array[A]
def aggregate(values: Array[A]): B
}
object StringHelper extends Helper[Byte, String] {
def decode(bytes: Array[Byte]): Array[Byte] = bytes.filter(_ != 0)
def aggregate(values: Array[Byte]): String = new String(values, StandardCharsets.UTF_8)
}
object IntHelper extends Helper[Int, Int] {
def decode(bytes: Array[Byte]): Array[Int] = bytes.map(_.toInt)
def aggregate(values: Array[Int]): Int = values.sum
}
def decodeAgg[A, B](bytes: Array[Byte], helper: Helper[A, B])(implicit ev: ClassTag[A]): B = {
val decoded = helper.decode(bytes)
val notFirstDecoded = decoded
.zipWithIndex
.filter({case (_, i) => i != 0})
.map(_._1)
.toArray
helper.aggregate(notFirstDecoded)
}
def main(args: Array[String]) {
val helper: Helper[_, _] = args(1) match {
case "int" => IntHelper
case "string" => StringHelper
case _ => throw new Exception("unknown data type")
}
val bytes = Array(97, 98, 99).map(_.toByte)
val aggregated = decodeAgg(bytes, helper)
println(s"aggregated to $aggregated")
}
}
Run with sbt "run -- string".
Full stack trace on this example:
[error] java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [B ([Ljava.lang.Object; and [B are in module java.base of loader 'bootstrap')
[error] at asdf.Main$StringHelper$.aggregate(Main.scala:12)
[error] at asdf.Main$.decodeAgg(Main.scala:29)
[error] at asdf.Main$.main(Main.scala:39)
I was using Scala 2.12, JDK 13.
I've tried using @specialized to no effect.