我正在尝试使用 json4s 库在Scala中创建一个类序列化的简单示例,但即使在互联网上广泛搜索它之后,很遗憾我无法找不到任何可以解决我问题的满意样本。
基本上我有一个名为Person
的简单类,我想从JSON字符串中提取此类的实例。
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 参数时,我收到此错误:
线程“main”中的异常org.json4s.package $ MappingException:没有可用的年龄值
我知道Person
类在其构造函数中有两个必需参数,但我想知道是否有办法通过解析器或类似方法进行转换。
另外,我试图制作这个解析器,但没有成功。
提前感谢您的帮助。
答案 0 :(得分:2)
假设您不希望通过将其类型设置为Option
来使年龄可选,那么您可以通过扩展CustomSerializer[Person]
来编写自定义序列化程序。自定义序列化程序采用Formats
到PartialFunction[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)
}))
这可能会被简化,因为有很多重复。此外,可能有一种更好的方法来递归调用序列化/反序列化。