大家好,最近我遇到了将json转换为我自己的数据模型的问题。
我有一个json格式的消息,可能包含一个空字符串:
{
"name" : "John Doe",
"hobbies": ""
}
或爱好类型列表:
{
"name" : "John Doe",
"hobbies": [{"name":"basketball"}]
}
以下是我在scala play框架中的案例类数据模型:
case class Person(name: String, hobbies: List[Hobby])
case class Hobby(name: String)
现在我使用默认的json格式化程序,但当我们将空字符串作为值时,它当然不能正常工作。
implicit val HobbyJson= Json.format[Hobby]
implicit val PersonJson = Json.format[Person]
如果hobbies
有一个空字符串,它将抛出异常。当它是空字符串时,我想将其转换为空列表。我搜索Play提供的文档,但无法找到信息。谁能提出一些建议?
提前致谢。
答案 0 :(得分:0)
正如您所提到的,由于Format
的处理方式不一致,默认的hobbies
宏对您不起作用。所以你需要实现自己的Reads[Person]
- 这就是我的方法:
object PersonJson {
implicit val hobbyConverter = Json.format[Hobby]
val personReads = new Reads[Person] {
override def reads(json: JsValue): JsResult[Person] = {
for {
personName <- (json \ "name").validate[String]
hobbies <- (json \ "hobbies").validate[JsValue]
} yield {
val maybeHobbyList = hobbies.validate[List[Hobby]].asOpt
Person(personName, maybeHobbyList.getOrElse(Nil))
}
}
}
implicit val personConverter = Format(personReads, Json.writes[Person])
}
这里需要注意的关键是围绕着JsResult
提供的理解和yield
。这为我们提供了所有必要的检查(例如name
字段在那里并且是字符串,并且hobbies
字段在那里。)
yield
块中的代码只有在我们看到非常接近Person
的内容时才会运行。然后,我们可以安全地尝试将hobbies
验证为List[Hobby]
,并将结果转换为Option[List[Hobby]]
。如果它不起作用它将是None
(因此它必须是一个字符串),因此我们根据需要将其默认为空列表。
答案 1 :(得分:0)
谢谢@millhouse的回答,这绝对有效。就像他说我们需要一个自定义Reads[Person]
来正确转换它。
我也发布了我的代码作为参考。
implicit val personJsonReads: Reads[Person] = (
(__ \ "name").read[String] and
(__ \ "hobbies").read[List[Hobby]].orElse(Reads.pure(List()))
) (Person.apply _)
当值无法转换为read[List[Hobby]].orElse(Reads.pure(List()))
时, List[Hobby]
将生成空列表。