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

在Scala中转换JSON对象时出现问题,json,scala,parsing,json4s,Json,Scala,Parsing,Json4s,我试图使用json4s库在Scala中创建一个类序列化的简单示例,但即使在internet上广泛搜索了它,不幸的是,我也找不到任何满意的示例来解决我的问题 基本上,我有一个名为Person的简单类,我想从JSON字符串中提取这个类的一个实例 case class Person( val name: String, val age: Int, val children: Option[List[Person]] ) 所以当我这样做的时候: val jsonStr = "{

我试图使用json4s库在Scala中创建一个类序列化的简单示例,但即使在internet上广泛搜索了它,不幸的是,我也找不到任何满意的示例来解决我的问题

基本上,我有一个名为
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
类在其构造函数中有两个必需的参数,但我想知道是否有方法通过解析器或类似的东西进行这种转换

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


提前感谢您的帮助。

假设您不想通过将其类型设置为
选项来选择年龄,那么您可以通过扩展
CustomSerializer[Person]
来编写自定义序列化程序。自定义序列化程序将函数从
格式
转换为
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)
}))

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

当没有“age”参数时,解析JSON的结果是什么?显然,您需要为age使用选项[Int]type或创建自定义序列化程序:@dan getz,我将从第三方应用程序接收这些JSON字符串,因此我不能保证所有参数都会出现在它们的请求中,因此,我只是想找出使解析器健壮的选项(我一周前才开始学习Scala语言)。@sap1ens,正如我所说,我试图使用这个精确的示例来制作这个解析器,但没有成功。无论如何,谢谢。“我的选项是什么?”您可以保留现有的异常,抛出不同的异常,返回一个
选项
,返回一个特殊值,使用
选项
作为
年龄
参数,使用一个特殊的
年龄
数字表示“未指定”,返回一个
尝试
任何一个
。。。这一清单不胜枚举。您是在请求帮助编写解析器,还是在决定您的代码首先应该做什么?非常感谢,@KuluLimpa!它像我预料的那样轻柔地工作。