java.lang.Исключение ClassCastException при десериализации объекта Scala

#scala #serialization #sbt #deserialization #ammonite

#scala #сериализация #sbt #десериализация #аммонит

Вопрос:

Итак, у меня есть такой объект

 case class QueryResult(events: List[Event])
 

что мне нужно сериализовать десериализацию. Для сериализации у меня есть этот неявный класс

   implicit class Serializer(obj: Object) {
    def serialize: Array[Byte] = {
      val stream = new ByteArrayOutputStream()
      val objectOutputStream = new ObjectOutputStream(stream)
      objectOutputStream.writeObject(obj)
      objectOutputStream.close
      stream.toByteArray
    }
  }
 

Он используется как

 val byteArray = QueryResult(events).serialize
 

Тогда для десриализации у меня есть эта черта, которая может быть расширена сопутствующим классом.

 trait Deserializer[A] {
  private type resultType = A
  def deserialize(bytes: Array[Byte]): A = {
    val objectInputStream = new ObjectInputStream(
      new ByteArrayInputStream(bytes)
    )
    val value = objectInputStream.readObject.asInstanceOf[resultType]
    objectInputStream.close
    value
  }
}
 

Вы бы использовали его следующим образом

 object QueryResult extends Deserializer[QueryResult]
 

Тогда вы должны иметь возможность восстановить экземпляр QueryResult из массива байтов следующим образом

 val QueryResult: QueryResult = QueryResult.deserialize(byteArray)
 

Проблема в том, что это иногда вызывает ошибку, подобную приведенной ниже

 java.lang.ClassCastException: cannot assign instance of scala.collection.generic.DefaultSerializationProxy to field co.app.QueryResult.events of type scala.collection.immutable.List in instance of co.app.QueryResult
  at java.base/java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2205)
  at java.base/java.io.ObjectStreamClass$FieldReflector.checkObjectFieldValueTypes(ObjectStreamClass.java:2168)
  at java.base/java.io.ObjectStreamClass.checkObjFieldValueTypes(ObjectStreamClass.java:1422)
  at java.base/java.io.ObjectInputStream.defaultCheckFieldValues(ObjectInputStream.java:2450)
  at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357)
  at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2166)
  at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1668)
  at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
  at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
  at co.app.Deserializer.deserialize(Types.scala:51)
  at co.app.Deserializer.deserialize$(Types.scala:47)
  at co.app.LocalStorage$QueryResults$.get(LocalStorage.scala:241)
  ... 36 elided

 

Теперь, когда я говорю «иногда», я имею в виду, что десериализация работает, когда я собираю код в jar и запускаю его с помощью java cli, но она прерывается, когда я пытаюсь выполнить этот код через sbt test , sbt console , или ammonite . Есть идеи, почему он ломается при таких обстоятельствах, и возможные предложения по исправлению?

Комментарии:

1. Как вы сериализуете объект, который пытаетесь десериализовать? Работает ли это, если вы сериализуете, а затем десериализуете в том же исполнении (т. Е. Что-то вроде deserialize(serialize(myObject)) )?

2. Обратите внимание, что я не знаю вашего варианта использования, но по умолчанию я бы не рекомендовал использовать сериализацию java. Для этого лучше использовать выделенную библиотеку.

3. @juh Ответ на ваш первый вопрос — нет, не всегда. Та же ошибка возникает, когда я пытаюсь выполнить serde в одной строке, но только при определенных обстоятельствах. Код работает нормально, когда я запускаю jar из java командной строки. Я обновил сообщение, чтобы объяснить, как я выполняю сериализацию. Возможно, вы правы, переход на выделенную библиотеку может быть правильным решением.