【问题标题】:How to serialize sealed abstract class with Json4s in Scala?如何在 Scala 中使用 Json4s 序列化密封抽象类?
【发布时间】:2018-08-10 12:51:21
【问题描述】:

如何在 Scala 中用 Json4s 序列化一个密封的抽象类?

定义了以下类:

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:解析的 JSON 值与类构造函数不匹配

我花了很多时间试图完成这项工作......

【问题讨论】:

    标签: scala serialization deserialization json-deserialization json4s


    【解决方案1】:

    经过大量谷歌搜索并仔细阅读 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)

    序列化:String = {"name":"Joe","age":35,"spouse":{"name":"Marilyn","age":33}}

    scala> val parsedObj = Serialization.readPerson

    parsedObj: Person = Customer(Joe,35,Spouse(Marilyn,33))

    【讨论】:

      最近更新 更多