Scala управление версией класса травления

Я хотел бы использовать трассировку scala для хранения двоичного представления класса case.

Я хотел бы знать, есть ли способ управлять версией класса case (способ, которым позволяет буфер протокола)


Вот мой пример

Я делаю программу в определенную дату со следующим классом case

case class MessageTest(a:String,b:String) 

Затем я сериализую экземпляр этого класса

import scala.pickling._
import binary._
val bytes=MessageTest("1","2").pickle

И затем я сохраняю результат в файл


Впоследствии я мог бы теперь сделать эволюцию на моем классе case, чтобы добавить новое необязательное поле

case class MessageTest (a:String,b:String,c:Option[String]=None)

Я хотел бы иметь возможность повторно использовать данные, которые я ранее сохранил в своем файле, десериализовать его и восстановить экземпляр класса case (со значением по умолчанию для нового параметра)

Но когда я использую следующий код

import scala.pickling._
import binary._
val messageback=bytes.unpickle[MessageTest]

Я получил следующую ошибку:

java.lang.ArrayIndexOutOfBoundsException: 26     at scala.pickling.binary.BinaryPickleReader $$ anonfun $2.apply(BinaryPickleFormat.scala: 446)     at scala.pickling.binary.BinaryPickleReader $$ anonfun $2.apply(BinaryPickleFormat.scala: 434)     at scala.pickling.PickleTools $class.withHints(Tools.scala: 498)     в scala.pickling.binary.BinaryPickleReader.withHints(BinaryPickleFormat.scala: 425)     at scala.pickling.binary.BinaryPickleReader.beginEntryNoTagDebug(BinaryPickleFormat.scala: 434)     в scala.pickling.binary.BinaryPickleReader.beginEntryNoTag(BinaryPickleFormat.scala: 431)


Я сделал что-то не так?

Существует ли способ, с помощью которого работает мой сценарий?

Привет

Ответ 1

Ну, проблема в том, что вы пытаетесь десериализоваться обратно на другой объект, чем то, к чему вы сериализовались.

Рассмотрим это. Первый объект

scala> case class MessageTest(a: String, b:String)
defined class MessageTest

scala> val bytes = MessageTest("a", "b").pickle
bytes: pickling.binary.pickleFormat.PickleType = BinaryPickle([0,0,0,81,36,108,105,110,101,53,49,46,36,114,101,97,100,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,77,101,115,115,97,103,101,84,101,115,116,0,0,0,1,97,0,0,0,1,98])

Теперь с измененным объектом объекта...

scala> case class MessageTest(a: String, b: String, c: Option[String] = None)
defined class MessageTest

scala> val bytes = MessageTest("a", "b").pickle
bytes: pickling.binary.pickleFormat.PickleType = BinaryPickle([0,0,0,81,36,108,105,110,101,53,51,46,36,114,101,97,100,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,36,105,119,46,77,101,115,115,97,103,101,84,101,115,116,0,0,0,1,97,0,0,0,1,98,0,0,0,15,115,99,97,108,97,46,78,111,110,101,46,116,121,112,101])

В этом случае библиотека не может знать, что вы имеете в виду, потому что она просто ожидает, что подписи совпадут.

https://github.com/scala/pickling/issues/39, но вы можете хотя бы пойти с ним одним способом. как показано здесь.

import scala.pickling._
import scala.pickling.Defaults._
import scala.pickling.binary._

case class LegacyMessage(a: String, b: String)
case class Message(a: String, b: String, c: Option[String] = None)

implicit val legacyUnpickler = Unpickler.generate[LegacyMessage]
implicit val messageUnpickler = Unpickler.generate[Message]

val legacyBytes = LegacyMessage("a", "b")
val msgBytes = Message("a", "b", None)

val pickledBytes = msgBytes.pickle
val pickledLegacy = legacyBytes.pickle

// New Message can Serialize back to Legacy Messages
val newToOld = pickledBytes.unpickle[LegacyMessage]

// Old Messages can not serialize up to the new message schema
// println(pickledLegacy.unpickle[Message])

val old = pickledLegacy.unpickle[LegacyMessage]

if(newToOld == old){
  println(true)
}

Надеюсь, это немного поможет.