Удалить tpe из json после сериализации с помощью скала-травления
Есть ли простой способ сериализации в JSON без поля "tpe" внутри объекта? Мне нужно сериализовать case-классы в структуры json, а затем отправить их по проводам (они не будут десериализованы в будущем). У меня есть конкретные API, так что.. Мне не нужны дополнительные поля.
Для класса Person
показано ниже:
case class Person(Name: String, Age: int, CandyLover: Boolean)
Я хотел бы видеть следующее:
{
"Name": "Paul",
"Age": 23,
"CandyLover": true
}
3 ответа
Наверное, самый простой способ сделать это - передать Hint
в JSONPickleBuilder
, Быстрый способ сделать это переопределить строителей в JSONPickleFormat
позвонив hintStaticallyElidedType()
метод из PickleTools
,
Вот своего рода фрагмент кода, чтобы продемонстрировать это:
import org.specs2.matcher.JsonMatchers
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import scala.pickling.Defaults._
import scala.pickling.json.{JSONPickleBuilder, JSONPickleFormat, JsonFormats}
import scala.pickling.{Output, PBuilder, PickleTools, StringOutput}
class PersonJsonFormatsTest extends Specification with JsonMatchers {
trait Context extends Scope with PersonJsonFormats
trait PersonJsonFormats extends JsonFormats {
override implicit val pickleFormat: JSONPickleFormat = new PersonJSONPickleFormat
}
class PersonJSONPickleFormat extends JSONPickleFormat {
override def createBuilder() = new JSONPickleBuilder(this, new StringOutput) with PickleTools {
hintStaticallyElidedType()
}
override def createBuilder(out: Output[String]): PBuilder = new JSONPickleBuilder(this, out) with PickleTools {
hintStaticallyElidedType()
}
}
"Pickle" should {
"Serialize Person without $type field in resulting JSON" in new Context {
case class Person(Name: String, Age: Int, CandyLover: Boolean)
val pickledPersonObject = Person("Paul", 23, CandyLover = true).pickle
println(pickledPersonObject.value)
pickledPersonObject.value must not */("$type" → ".*".r)
}
}
}
Выход из println(pickledPersonObject.value)
будет так, как вам нужно:
{
"Name": "Paul",
"Age": 23,
"CandyLover": true
}
Таким образом, вы будете оставаться в курсе дальнейших обновлений рассола.
PS Если кто-то знает более изящный и удобный способ достичь такого же поведения - сообщите нам об этом:-)
Я бы посоветовал вам взглянуть на спрей-джон или аргонавт. Или play-json, если вы уже используете Play.
Scala pickling на самом деле не является библиотекой json, она не была создана для генерации JSON для общедоступного API, она не гибкая, вы не можете сначала определить протокол JSON, а затем обеспечить сериализацию выбора для соответствия протоколу. Pickling предназначен для сериализации между компьютерами, где никто не заботится о байтах, проходящих между приложениями.
Для маринования скалы 0.10.x:
import scala.pickling._
import scala.pickling.json.{JSONPickle, JSONPickleBuilder, JSONPickleFormat, JsonFormats}
import scala.pickling.pickler.AllPicklers
object serialization extends JsonFormats with Ops with AllPicklers {
override implicit val pickleFormat: JSONPickleFormat = new JSONPickleFormat {
private def setHints(h: Hintable): Unit = {
h.hintStaticallyElidedType()
h.hintDynamicallyElidedType()
}
override def createBuilder(): JSONPickleBuilder = {
val builder = super.createBuilder()
setHints(builder)
builder
}
override def createBuilder(out: Output[String]): PBuilder = {
val builder = super.createBuilder(out)
setHints(builder)
builder
}
override def createReader(pickle: JSONPickle): PReader = {
val reader = super.createReader(pickle)
setHints(reader)
reader
}
}
}
object SerializationTest extends App {
import serialization._
case class Person(firstName: String, lastName: String)
val pickle: JSONPickle = Person("Evelyn", "Patterson").pickle
val jsonString: String = pickle.value // {"firstName": "Evelyn","lastName": "Patterson"}
val person: Person = jsonString.unpickle[Person]
}
Для маринования скалы 0.11.x:
import scala.pickling._
import scala.pickling.json.{JSONPickle, JSONPickleBuilder, JSONPickleFormat}
import scala.pickling.pickler.AllPicklers
object serialization extends AllPicklers {
private final class CustomJSONPickleFormat(tag: FastTypeTag[_]) extends JSONPickleFormat {
private def setHints(h: Hintable) {
h.hintElidedType(tag)
}
override def createBuilder(): JSONPickleBuilder = {
val b = super.createBuilder()
setHints(b)
b
}
override def createBuilder(out: Output[String]): PBuilder = {
val b = super.createBuilder(out)
setHints(b)
b
}
override def createReader(pickle: JSONPickle): PReader = {
val b = super.createReader(pickle)
setHints(b)
b
}
}
implicit val staticOnly = static.StaticOnly // for compile time serialization methods generation
implicit final class EncodeDecodeOps[T](picklee: T) {
def encode(implicit pickler: Pickler[T]): String = {
val pickleFormat = new CustomJSONPickleFormat(pickler.tag)
functions.pickle(picklee)(pickleFormat, pickler).value
}
def decode[A](implicit c: T => String, unpickler: Unpickler[A]): A = {
val pickleFormat = new CustomJSONPickleFormat(unpickler.tag)
functions.unpickle[A](json.JSONPickle(picklee))(unpickler, pickleFormat)
}
}
}
case class Person(firstName: String, lastName: String) {
@transient var x = "test"
}
object SerializationTest extends App {
import serialization._
val jsonString = Person("Lisa", "Daniels").encode
println(jsonString)
val person = jsonString.decode[Person]
println(person)
}