PlayJson Scala 读取可空字段
PlayJson Scala Read Nullable Fields
我有一个联系人 class,
它的名字是 (JsPath \ "contact_name" \ "first_name" )
,但是 (JsPath \ "contact_name")
可以是空的。
有人知道如何为这种情况 Reader 做 class 吗?
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"
}
在没有 "contact_name" 的情况下联系 Json
:
{
"phone_number": "1231231234",
"email": "test@gmail.com"
}
我希望 Json
都能够读取联系人对象。谢谢。
假设您的 phone 电话号码和电子邮件是联系方式的一部分,下面是一个可行的方法(您可以使用 \
深入搜索路径):
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),)
我确实在上面写了一个 post - 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"
提取 firstName 和 lastName
为了简化事情我做了这样的事情(尽管它确实创建了很多 classes):
假设:contact_name 是可选的,您希望将整个事情折叠成一个案例 class 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)
}
实际上,我有单独的案例 classes 来表示每个 JSON 节点和一个转换器函数来将 Scala JSON 表示转换为我的模型 class .如果您有重复值(例如:同一个 JSON 文档中有多个联系人对象,因此会出现多个 first_name 元素),这会很有效。尽管在您的特定示例中,最好跳过 Raw classes 并在您的模型中创建两个案例 classes:Contact
和 ContactName
但我想演示将视图模型 (Raw...
) 与内部模型分开的通用解决方案。
我有一个联系人 class,
它的名字是 (JsPath \ "contact_name" \ "first_name" )
,但是 (JsPath \ "contact_name")
可以是空的。
有人知道如何为这种情况 Reader 做 class 吗?
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"
}
在没有 "contact_name" 的情况下联系 Json
:
{
"phone_number": "1231231234",
"email": "test@gmail.com"
}
我希望 Json
都能够读取联系人对象。谢谢。
假设您的 phone 电话号码和电子邮件是联系方式的一部分,下面是一个可行的方法(您可以使用 \
深入搜索路径):
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),)
我确实在上面写了一个 post - 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"
为了简化事情我做了这样的事情(尽管它确实创建了很多 classes):
假设:contact_name 是可选的,您希望将整个事情折叠成一个案例 class 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)
}
实际上,我有单独的案例 classes 来表示每个 JSON 节点和一个转换器函数来将 Scala JSON 表示转换为我的模型 class .如果您有重复值(例如:同一个 JSON 文档中有多个联系人对象,因此会出现多个 first_name 元素),这会很有效。尽管在您的特定示例中,最好跳过 Raw classes 并在您的模型中创建两个案例 classes:Contact
和 ContactName
但我想演示将视图模型 (Raw...
) 与内部模型分开的通用解决方案。