在 Scala 中转换 JSON 个对象时出现问题

Problems converting JSON objects in Scala

我正在尝试使用 json4s 库在 Scala 中制作一个 class 序列化 的简单示例,但即使在互联网上广泛搜索后,不幸的是我找不到任何可以解决我问题的令人满意的示例。

基本上我有一个名为 Person 的简单 class,我想从 JSON 字符串中提取此 class 的一个实例。

case class Person(
    val name: String,
    val age: Int,
    val children: Option[List[Person]]
)

所以当我这样做时:

val jsonStr = "{\"name\":\"Socrates\", \"age\": 70}"
println(Serialization.read[Person](jsonStr))

我得到这个输出:

"Person(Socrates,70,None)" // works fine!

但是当我在 JSON 字符串中没有 age 参数时,我得到这个错误:

Exception in thread "main" org.json4s.package$MappingException: No usable value for age

我知道 Person class 在它的构造函数中有两个必需的参数,但我想知道是否有办法通过解析器或类似的东西进行这种转换。

此外,我尝试制作此解析器,但没有成功。

在此先感谢您的帮助。

假设您不想通过将其类型设置为 Option 来使年龄可选,那么您可以通过扩展 CustomSerializer[Person] 来编写自定义序列化程序。自定义序列化器采用从 FormatsPartialFunction[JValue, Person](您的 Person 反序列化器)和 PartialFunction[Any, JValue](您的序列化器)的元组的函数。

假设 Person.DefaultAge 是您要为年龄设置的默认值(如果未给出年龄),那么自定义序列化程序可能如下所示:

object PersonSerializer extends CustomSerializer[Person](formats => ( {
  case JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: Nil) => Person(name, age.toInt, None)
  case JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: JField("children", JArray(children)) :: Nil) => Person(name, age.toInt, Some(children map (child => formats.customDeserializer(formats).apply(TypeInfo(classOf[Person], None), child).asInstanceOf[Person])))
  case JObject(JField("name", JString(name)) :: Nil) => Person(name, Person.DefaultAge, None)
  case JObject(JField("name", JString(name)) :: JField("children", JArray(children)) :: Nil) => Person(name, Person.DefaultAge, Some(children map (child => formats.customDeserializer(formats).apply(TypeInfo(classOf[Person], None), child).asInstanceOf[Person])))
}, {
  case Person(name, age, None) => JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: Nil)
  case Person(name, age, Some(children)) => JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: JField("children", formats.customSerializer(formats).apply(children)) :: Nil)
}))

这可能会被简化,因为有很多重复。此外,可能有更好的方法来递归调用 serialization/deserialization。