【问题标题】:PlayJson Scala Read Nullable Fields播放 Json Scala 读取可空字段
【发布时间】:2016-05-03 11:13:47
【问题描述】:

我有一个联系人类,
它将(JsPath \ "contact_name" \ "first_name" ) 读作firstName,但(JsPath \ "contact_name") 可以为空。
有人知道如何为这个案例课做阅读器吗?

case class Contact(var firstName: Option[String],
                   var lastName: Option[String])

我的联系人Json 是:

{
  "contact_name": {
     "first_name": "hello",
     "last_name": "world"
  },
  "phone_number": "1231231234",
  "email": "test@gmail.com"
}

联系Json 不带“contact_name”:

{
  "phone_number": "1231231234",
  "email": "test@gmail.com"
}

我希望两个Json 都能够读取联系人对象。谢谢。

【问题讨论】:

    标签: json scala playframework-2.0


    【解决方案1】:

    假设您的电话号码和电子邮件是联系方式的一部分,这里是可行的(您可以使用\\ 来深入搜索路径):

    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    
    case class Contact(firstName: Option[String], lastName: Option[String],
                        phone: String, email: String)
    
    val contactReads: Reads[Contact] = (
      (__ \\ "first_name").readNullable[String] and
      (__ \\ "last_name").readNullable[String] and
      (__ \ "phone_number").read[String] and
      (__ \ "email").read[String]
    )(Contact.apply _)
    
    val json1 = """{
       | "contact_name": {
       |    "first_name": "hello",
       |    "last_name": "world"
       |  },
       |  "phone_number": "1231231234",
       |  "email": "test@gmail.com"
       |}""".stripMargin
    
    Json.parse(json1).validate[Contact](contactReads)
    // JsSuccess(Contact(Some(hello),Some(world),1231231234,test@gmail.com),)
    
    val json2 = """{
       |  "phone_number": "1231231234",
       |  "email": "test@gmail.com"
       |}""".stripMargin
    
    Json.parse(json2).validate[Contact](contactReads)
    // JsSuccess(Contact(None,None,1231231234,test@gmail.com),)
    

    【讨论】:

      【解决方案2】:

      我确实写过一篇文章 - http://pedrorijo.com/blog/scala-json/

      它介绍了如何将 json 读取到案例类。具体来说,从 json 读取可选字段,在最后一个示例中:

      case class User(username: String, friends: Int, enemies: Int, isAlive: Option[Boolean])
      
      object User {
      
        import play.api.libs.functional.syntax._
        import play.api.libs.json._
      
        implicit val userReads: Reads[User] = (
            (JsPath \ "username").read[String] and
            (JsPath \ "friends").read[Int] and
            (JsPath \ "enemies").read[Int] and
            (JsPath \ "is_alive").readNullable[Boolean]
          ) (User.apply _)
      }
      

      这应该足以让您完成它。 此外,如果json 是一个包含所需字段的字符串,您可以只写:

      Json.parse(json)
      

      所以,如果 fullJson 是完整的 Json 对象(带有那些不需要的字段),您可以使用 fullJson \ "contact_name" 提取名字和姓氏

      【讨论】:

        【解决方案3】:

        为了简化事情,我做了这样的事情(尽管它确实创建了很多类):

        假设:contact_name 是可选的,并且您希望将整个内容折叠成单个案例类Contact

        {
          "contact_name": {
             "first_name": "hello",
             "last_name": "world"
          },
          "phone_number": "1231231234",
          "email": "test@gmail.com"
        }
        
        
        case class Contact(firstName: Optional[String], lastName: Optional[String], phoneNumber: String, email: String)
        
        case class RawContactName(firstName: String, lastName: String)
        case class RawContact(contactName: Optional[RawContactName], phoneNumber: String, email: String)
        
        implicit val rawContactReads: Reads[RawContact] = (
              (JsPath \ "contact_name").readNullable[RawContactName] and
              (JsPath \ "phone_number").read[String] and
              (JsPath \ "email").read[String]
            ) (RawContact.apply _)
        
        implicit val rawContactNameReads: Reads[RawContactName] = (
              (JsPath \ "first_name").read[String] and
              (JsPath \ "last_name").read[String]
            ) (RawContactName.apply _)
        
        def transformContact(rawContact: RawContact): Contact = {
            val (maybeFirstName, maybeLastName) = rawContact.contactName match {
                case Some(RawContactName(firstName, lastName)) => (Some(firstName), Some(lastName))
                case None => (None, None)
            }
            Contact(maybeFirstName, maybeLastName, rawContact.phoneNumber, rawContact.email)
        }
        

        实际上,我有单独的案例类来表示每个 JSON 节点和一个转换器函数来将 Scala JSON 表示转换为我的模型类。如果您有重复的值(例如:同一个 JSON 文档中有多个联系人对象,因此会出现多个 first_name 元素),这将很有效。尽管在您的具体示例中,最好跳过 Raw 类并在模型中创建两个案例类:ContactContactName 但我想演示一个将 View 模型(Raw...)与内部模型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-01-11
          • 1970-01-01
          • 1970-01-01
          • 2018-05-03
          • 2016-06-01
          • 2014-01-04
          • 2016-03-07
          相关资源
          最近更新 更多