Маринование скалы: как?
Я пытаюсь использовать сериализацию "травления" в Scala, и я вижу тот же пример, демонстрирующий это:
import scala.pickling._
import json._
val pckl = List(1, 2, 3, 4).pickle
Разрыхление так же просто, как травление:
val lst = pckl.unpickle[List[Int]]
Этот пример поднимает некоторый вопрос. Прежде всего, он пропускает преобразование объекта в строку. По-видимому, вам нужно вызвать pckl.value, чтобы получить строковое представление json.
Распахивание еще более сбивает с толку. Десериализация - это процесс превращения строки (или байтов) в объект. Почему этот "пример" демонстрирует десериализацию, если нет строкового / двоичного представления объекта?
Итак, как мне десериализовать простой объект с помощью библиотеки травления?
3 ответа
Используйте систему типов и тематические классы для достижения ваших целей. Вы можете отменить выбор какого-либо более высокого типа в вашей иерархии (вплоть до AnyRef). Вот пример:
trait Zero
case class One(a:Int) extends Zero
case class Two(s:String) extends Zero
object Test extends App {
import scala.pickling._
import json._
// String that can be sent down a wire
val wire: String = Two("abc").pickle.value
// On the other side, just use a case class
wire.unpickle[Zero] match {
case One(a) => println(a)
case Two(s) => println(s)
case unknown => println(unknown.getClass.getCanonicalName)
}
}
Хорошо, я думаю, что понял это.
import scala.pickling._
import json._
var str = Array(1,2,3).pickle.value // this is JSON string
println(str)
val x = str.unpickle[Array[Int]] // unpickle from string
выдаст строку JSON:
{
"tpe": "scala.Array[scala.Int]",
"value": [
1,
2,
3
]
}
Итак, так же, как мы выбираем любой тип, мы можем удалить строку. Тип сериализации регулируется неявным форматером, объявленным в "json", и может быть заменен "двоичным".
Похоже, вы начнете с рассола, чтобы распаковать его в классе дел. Но строка JSON может быть передана в класс JSONPickle, чтобы получить начальный указатель.
Вот пример, основанный на их тесте array-json
package so
import scala.pickling._
import json._
case class C(arr: Array[Int]) { override def toString = s"""C(${arr.mkString("[", ",", "]")})""" }
object PickleTester extends App {
val json = """{"arr":[ 1, 2, 3 ]}"""
val cPickle = JSONPickle( json )
val unpickledC: C = cPickle.unpickle[C]
println( s"$unpickledC, arr.sum = ${unpickledC.arr.sum}" )
}
Вывод на печать:
C([1,2,3]), arr.sum = 6
Я был в состоянии выкинуть "tpe" из теста, а также .stripMargin.trim
на входе JSON из теста. Все работает в одну строку, но я подумал, что это может быть более очевидным разделением. Мне неясно, должен ли этот "tpe" из теста обеспечивать меру безопасности типов для входящего JSON.
Похоже, единственный другой класс, который они поддерживают для маринования, - это BinaryPickle, если вы не хотите выкатить свой собственный. В последнем jar-снимке scala-pickling требуются кавычки для компиляции кода в этом ответе.
Этим утром я попытался сделать что-то более сложное и обнаружил, что "tpe" требуется для непримативов во входящем JSON - что указывает на то, что сериализованная строка действительно должна быть совместима со средством выбора (которое я смешал с приведенным выше кодом):
case class J(a: Option[Boolean], b: Option[String], c: Option[Int]) { override def toString = s"J($a, $b, $c)" }
...
val jJson = """{"a": {"tpe": "scala.None.type"},
| "b":{"tpe": "scala.Some[java.lang.String]","x":"donut"},
| "c":{"tpe": "scala.Some[scala.Int]","x":47}}"""
val jPickle = JSONPickle( jJson.stripMargin.trim )
val unpickledJ: J = jPickle.unpickle[J]
println( s"$unpickledJ" )
...
где, естественно, я должен был использовать .value
на J(None, Some("donut"), Some(47))
выяснить, как создать jJson
входное значение, чтобы исключить выбрасывание исключением.
Выход для J
как:
J(None, Some(donut), Some(47))
Глядя на этот тест, кажется, что если входящий JSON - это все примитивы или классы дел (или комбинации), то магия JSONPickle работает, но некоторым другим классам, таким как Options, требуется дополнительная информация о типе "tpe" для правильной распаковки.