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

blz*_*lzn 5 parsing json scala json4s

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

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

case class Person(
    val name: String,
    val age: Int,
    val children: Option[List[Person]]
)
Run Code Online (Sandbox Code Playgroud)

所以当我这样做时:

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

我得到这个输出:

"Person(Socrates,70,None)" // works fine!
Run Code Online (Sandbox Code Playgroud)

但是当我的JSON 字符串中没有年龄参数时,我收到此错误:

线程“main”org.json4s.package$MappingException 中出现异常:年龄没有可用值

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

另外,我尝试过制作这个解析器,但没有成功。

预先感谢您的任何帮助。

Kul*_*mpa 2

假设您不想通过将其类型设置为 来使其成为可选的Option,那么您可以通过扩展来编写自定义序列化程序CustomSerializer[Person]。自定义序列化器将一个函数从(您的反序列化器)和(您的序列化器)Formats的元组中获取。PartialFunction[JValue, Person]PersonPartialFunction[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)
}))
Run Code Online (Sandbox Code Playgroud)

这可能可以简化,因为有很多重复。此外,可能有更好的方法来递归调用序列化/反序列化。