简体   繁体   English

播放框架json从空字符串读取到空列表

[英]play framework json reads from empty string to empty list

Hi everyone recently I faced an issue in converting json into my own data model. 大家好,最近我在将json转换为自己的数据模型时遇到了一个问题。

I have a json format message which may contain an empty string: 我有一个json格式的消息,其中可能包含一个空字符串:

{
    "name" : "John Doe", 
    "hobbies": ""
}

or a list of hobby types: 或爱好类型列表:

{
    "name" : "John Doe", 
    "hobbies": [{"name":"basketball"}]
}

And the following is my case class data model in scala play framework: 以下是我在scala play框架中的案例类数据模型:

case class Person(name: String, hobbies: List[Hobby])
case class Hobby(name: String)

Right now I'm using the default json formatter but of course it's not working well when we have empty string as value. 现在,我正在使用默认的json格式化程序,但是当我们将空字符串作为值时,它当然不能很好地工作。

implicit val HobbyJson= Json.format[Hobby]
implicit val PersonJson = Json.format[Person]

it will throw exception if the hobbies has a empty string. 如果hobbies有一个空字符串,它将抛出异常。 I want to convert it into an empty list when it's the empty string. 当它为空字符串时,我想将其转换为空列表。 I search the document Play provides but couldn't find infomation. 我搜索了Play提供的文档,但找不到信息。 Can anyone give some suggestions? 任何人都可以提出建议吗?

Thanks in advance. 提前致谢。

As you mentioned, the default Format macros won't work for you here because of the inconsistent treatment of hobbies . 如前所述,默认的Format宏在这里对您不起作用,因为hobbies处理方式不一致。 So you need to implement your own Reads[Person] - here's how I'd do it: 因此,您需要实现自己的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])
}

The key thing to note here is surrounding the whole thing in a JsResult courtesy of the for-comprehension and the yield . 这里要注意的关键是,出于理解和yield的考虑, JsResult中包含了整个内容。 This gives us all the necessary checking (like the name field being there and being a String, and the hobbies field being there). 这为我们提供了所有必要的检查(例如, name字段在那里并且是String,而hobbies字段在那里)。

The code within the yield block only runs if we've got something that looks pretty close to a Person . 仅当我们拥有看起来非常接近Person东西时, yield块中的代码才运行。 Then we can safely try validating the hobbies as a List[Hobby] , and convert the result to an Option[List[Hobby]] . 然后,我们可以安全地尝试将hobbies验证为List[Hobby] ,并将结果转换为Option[List[Hobby]] It'll be a None if it didn't work (thus it must have been a string) and so we default it to the empty list as required. 如果不起作用,它将为None (因此它必须是字符串),因此我们根据需要将其默认为空列表。

Thanks @millhouse answer, it definitely works. 谢谢@millhouse的回答,它肯定可以工作。 Like he said we need a custom Reads[Person] to properly convert it. 就像他说的那样,我们需要一个自定义的Reads[Person]来正确转换它。

I also post my code as reference. 我还将代码发布为参考。

  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())) will generate the empty list when the value cannot convert to List[Hobby] . 当值无法转换为List[Hobby]时, read[List[Hobby]].orElse(Reads.pure(List()))将生成一个空列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM