如何在 Scala 中使用 Json4s 序列化密封摘要 class?
How to serialize sealed abstract class with Json4s in Scala?
如何在 Scala 中使用 Json4s 序列化密封的摘要 class?
定义了以下 classes:
sealed abstract class Person extends Product with Serializable
case class Spouse(name: String, age: Int) extends Person
case class Customer(name: String, age: Int, spouse: Spouse) extends Person
我创建了一个客户类型的对象:
val customer: Customer = Customer("Joe", 35, Spouse("Marilyn", 33))
然后我序列化为JSON:
implicit val formats = DefaultFormats
val serialized = write(customer)
效果很好。但后来我尝试反序列化:
val parsedObj = Serialization.read[Person](serialized)
这里我不断收到错误:
org.json4s.package$MappingException: Parsed JSON values do not match with class constructor
我花了很多时间来完成这项工作...
经过大量谷歌搜索并仔细阅读 Json4s 文档后,我发现我需要一个自定义序列化程序才能使其正常工作。
但是,我花了一段时间才弄清楚 I need to set the formats 实际使用自定义序列化程序。
这是适合我的代码。
简单示例:
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.native.Serialization.{read, write}
import org.json4s.native.Serialization
sealed abstract class Person extends Product with Serializable
case class Spouse(name: String, age: Int) extends Person
case class Customer(name: String, age: Int, spouse: Spouse) extends Person
val customer: Customer = Customer("Joe", 35, Spouse("Marilyn", 33))
implicit val formats = Serialization.formats(NoTypeHints) + PersonSerializer
val serialized = write(customer)
val parsedObj = Serialization.read[Person](serialized)
自定义序列化程序:
object PersonSerializer extends Serializer[Person] {
private val PersonClass = classOf[Person]
def deserialize(implicit format: Formats)
: PartialFunction[(TypeInfo, JValue), Person] = {
case (TypeInfo(PersonClass, _), json) =>
json match {
case JObject(List(
JField("name", JString(d)),
JField("age", JInt(f)),
("spouse", JObject(List(JField("name", JString(g)), JField("age", JInt(h)))))
)) => Customer(d, f.toInt, Spouse(g, h.toInt))
case JObject(List(
JField("name", JString(d)),
JField("age", JInt(f))
)) => Spouse(d, f.toInt)
}
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: Customer =>
JObject(List(
JField("name", JString(x.name)),
JField("age", JInt(x.age)),
("spouse", JObject(List(JField("name", JString(x.spouse.name)), JField("age", JInt(x.spouse.age)))))
))
case x: Spouse =>
JObject(List(
JField("name", JString(x.name)),
JField("age", JInt(x.age))
))
}
}
输出
scala> val serialized = write(customer)
serialized: String = {"name":"Joe","age":35,"spouse":{"name":"Marilyn","age":33}}
scala> val parsedObj = Serialization.readPerson
parsedObj: Person = Customer(Joe,35,Spouse(Marilyn,33))
如何在 Scala 中使用 Json4s 序列化密封的摘要 class?
定义了以下 classes:
sealed abstract class Person extends Product with Serializable
case class Spouse(name: String, age: Int) extends Person
case class Customer(name: String, age: Int, spouse: Spouse) extends Person
我创建了一个客户类型的对象:
val customer: Customer = Customer("Joe", 35, Spouse("Marilyn", 33))
然后我序列化为JSON:
implicit val formats = DefaultFormats
val serialized = write(customer)
效果很好。但后来我尝试反序列化:
val parsedObj = Serialization.read[Person](serialized)
这里我不断收到错误:
org.json4s.package$MappingException: Parsed JSON values do not match with class constructor
我花了很多时间来完成这项工作...
经过大量谷歌搜索并仔细阅读 Json4s 文档后,我发现我需要一个自定义序列化程序才能使其正常工作。
但是,我花了一段时间才弄清楚 I need to set the formats 实际使用自定义序列化程序。
这是适合我的代码。
简单示例:
import org.json4s._
import org.json4s.native.JsonMethods._
import org.json4s.native.Serialization.{read, write}
import org.json4s.native.Serialization
sealed abstract class Person extends Product with Serializable
case class Spouse(name: String, age: Int) extends Person
case class Customer(name: String, age: Int, spouse: Spouse) extends Person
val customer: Customer = Customer("Joe", 35, Spouse("Marilyn", 33))
implicit val formats = Serialization.formats(NoTypeHints) + PersonSerializer
val serialized = write(customer)
val parsedObj = Serialization.read[Person](serialized)
自定义序列化程序:
object PersonSerializer extends Serializer[Person] {
private val PersonClass = classOf[Person]
def deserialize(implicit format: Formats)
: PartialFunction[(TypeInfo, JValue), Person] = {
case (TypeInfo(PersonClass, _), json) =>
json match {
case JObject(List(
JField("name", JString(d)),
JField("age", JInt(f)),
("spouse", JObject(List(JField("name", JString(g)), JField("age", JInt(h)))))
)) => Customer(d, f.toInt, Spouse(g, h.toInt))
case JObject(List(
JField("name", JString(d)),
JField("age", JInt(f))
)) => Spouse(d, f.toInt)
}
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: Customer =>
JObject(List(
JField("name", JString(x.name)),
JField("age", JInt(x.age)),
("spouse", JObject(List(JField("name", JString(x.spouse.name)), JField("age", JInt(x.spouse.age)))))
))
case x: Spouse =>
JObject(List(
JField("name", JString(x.name)),
JField("age", JInt(x.age))
))
}
}
输出
scala> val serialized = write(customer)
serialized: String = {"name":"Joe","age":35,"spouse":{"name":"Marilyn","age":33}}
scala> val parsedObj = Serialization.readPerson
parsedObj: Person = Customer(Joe,35,Spouse(Marilyn,33))