使用 play framework 和 scala 检查或查找 json 中是否存在特定路径
Check or find if a particular path exists in json using play framework and scala
我正在尝试使用 play 框架将 json 解析为案例 class。我的目的是检查 json 中是否存在特定路径。如果存在则只读取该路径中的元素。
这是我的代码
package com.learning.avinash.query
import play.api.libs.json.{JsDefined, JsPath, Json, Reads, Writes, __}
import play.api.libs.functional.syntax._
object ParseJson extends App {
case class Msisdn(primaryId: Option[String], relatedAccountId: Option[String])
object Msisdn {
implicit val readData: Reads[Msisdn] = (
(JsPath \ "primary-id").readNullable[String] ~
(JsPath \ "meta" \ "related-account-id").readNullable[String]
) (Msisdn.apply _)
}
val testJson = """{
"resources": [
{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823468684",
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
},
{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823467689"
}
]
}"""
println((Json.parse(testJson) \ "resources").as[List[Msisdn]])
}
在第二个对象的资源数组中,您可以观察到此代码完全缺失
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
现在,当我尝试解析 json 时,它失败了,并且出现以下异常
Exception in thread "main" play.api.libs.json.JsResultException: JsResultException(errors:List(((1)/meta/related-accoount-id,List(JsonValidationError(List(error.path.missing),WrappedArray())))))
是否有一个预定义的 function/method 正在播放,以便我可以检查这个
(JsPath \ "meta")
特定路径存在,然后只读取该路径中的元素。
或者我应该写一个自定义函数来检查路径是否存在。
我可以看到一个需要 Jsvalue 的 JsDefined()。
https://www.playframework.com/documentation/2.7.x/api/scala/play/api/libs/json/index.html
final case classJsDefined(value: JsValue)
Wrapper for JsValue to represent an existing Json value.
请提供任何想法、想法、帮助或建议。
可能会有帮助...
第一种方法是使用 Json.format
:
import play.api.libs.json._
object ParseJson extends App {
case class Msisdn(`primary-id`: Option[String], meta: Option[Meta])
case class Meta(`related-account-id`: Option[String])
implicit val metaFormat = Json.format[Meta]
implicit val msisdnFormat = Json.format[Msisdn]
输出:
List(Msisdn(Some(393823468684),Some(Meta(Some(10001771)))), Msisdn(Some(393823467689),None))
然后你可以使用
case class Msisdn(private val `primary-id`: Option[String],
private val meta: Option[Meta]) {
def primaryId: Option[String] = `primary-id`
def accountId: Option[String] = meta.flatMap(_.`related-account-id`)
}
改变publicAPI.
第二种方法是使用 recursive path。不过我觉得你可以慎重使用。
case class Msisdn(primaryId: Option[String], relatedAccountId: Option[String])
object Msisdn {
implicit val readData: Reads[Msisdn] = (
(JsPath \ "primary-id").readNullable[String] ~
(JsPath \ "related-account-id").readNullable[String]
) (Msisdn.apply _)
}
第三次使用 new Format
。在这种情况下,您可以使用 json 对象,并检查该字段是否存在。
还有一个方法,忘记怎么做了。它的使用方式 fmap
,可能。
对不起我的英语。
没有 flatten annotation 可用,但遵守规则更容易。
import play.api.libs.json._
case class MsisdnMeta(relatedAccountId: Option[String])
object MsisdnMeta {
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming { _ => "related-account-id" })
implicit val format: OFormat[MsisdnMeta] = Json.format
}
case class Msisdn(
primaryId: Option[String],
meta: Option[MsisdnMeta]) {
@inline def relatedAccountId: Option[String] =
meta.flatMap(_.relatedAccountId)
}
object Msisdn {
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming {
case "primaryId" => "primary-id"
case _ => "meta"
})
implicit val format: OFormat[Msisdn] = Json.format
}
然后reading/parsing JSON:
val json = Json.parse("""{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823468684",
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
}""")
val res = json.validate[Msisdn]
// play.api.libs.json.JsResult[Msisdn] = JsSuccess(Msisdn(Some(393823468684),Some(MsisdnMeta(Some(10001771)))),)
res.foreach { suc =>
println(s"relatedAccountId = ${suc.relatedAccountId}")
}
// relatedAccountId = Some(10001771)
... 并写入 JSON:
Json.toJson(Msisdn(Some("id"), Some(MsisdnMeta(Some("bar")))))
// play.api.libs.json.JsValue = {"primary-id":"id","meta":{"related-account-id":"bar"}}
通过将一些工厂添加到伴随对象,使用嵌套元创建 Msisdn
会更容易。
object Msisdn {
// Added factory
@inline def apply(
primaryId: Option[String],
relatedAccountId: String): Msisdn =
Msisdn(primaryId, Some(MsisdnMeta(Some(relatedAccountId))))
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming {
case "primaryId" => "primary-id"
case _ => "meta"
})
implicit val format: OFormat[Msisdn] = Json.format
}
Json.toJson(Msisdn(Some("id"), "bar"))
// play.api.libs.json.JsValue = {"primary-id":"id","meta":{"related-account-id":"bar"}}
我正在尝试使用 play 框架将 json 解析为案例 class。我的目的是检查 json 中是否存在特定路径。如果存在则只读取该路径中的元素。
这是我的代码
package com.learning.avinash.query
import play.api.libs.json.{JsDefined, JsPath, Json, Reads, Writes, __}
import play.api.libs.functional.syntax._
object ParseJson extends App {
case class Msisdn(primaryId: Option[String], relatedAccountId: Option[String])
object Msisdn {
implicit val readData: Reads[Msisdn] = (
(JsPath \ "primary-id").readNullable[String] ~
(JsPath \ "meta" \ "related-account-id").readNullable[String]
) (Msisdn.apply _)
}
val testJson = """{
"resources": [
{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823468684",
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
},
{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823467689"
}
]
}"""
println((Json.parse(testJson) \ "resources").as[List[Msisdn]])
}
在第二个对象的资源数组中,您可以观察到此代码完全缺失
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
现在,当我尝试解析 json 时,它失败了,并且出现以下异常
Exception in thread "main" play.api.libs.json.JsResultException: JsResultException(errors:List(((1)/meta/related-accoount-id,List(JsonValidationError(List(error.path.missing),WrappedArray())))))
是否有一个预定义的 function/method 正在播放,以便我可以检查这个
(JsPath \ "meta")
特定路径存在,然后只读取该路径中的元素。 或者我应该写一个自定义函数来检查路径是否存在。
我可以看到一个需要 Jsvalue 的 JsDefined()。
https://www.playframework.com/documentation/2.7.x/api/scala/play/api/libs/json/index.html
final case classJsDefined(value: JsValue)
Wrapper for JsValue to represent an existing Json value.
请提供任何想法、想法、帮助或建议。
可能会有帮助...
第一种方法是使用 Json.format
:
import play.api.libs.json._
object ParseJson extends App {
case class Msisdn(`primary-id`: Option[String], meta: Option[Meta])
case class Meta(`related-account-id`: Option[String])
implicit val metaFormat = Json.format[Meta]
implicit val msisdnFormat = Json.format[Msisdn]
输出:
List(Msisdn(Some(393823468684),Some(Meta(Some(10001771)))), Msisdn(Some(393823467689),None))
然后你可以使用
case class Msisdn(private val `primary-id`: Option[String],
private val meta: Option[Meta]) {
def primaryId: Option[String] = `primary-id`
def accountId: Option[String] = meta.flatMap(_.`related-account-id`)
}
改变publicAPI.
第二种方法是使用 recursive path。不过我觉得你可以慎重使用。
case class Msisdn(primaryId: Option[String], relatedAccountId: Option[String])
object Msisdn {
implicit val readData: Reads[Msisdn] = (
(JsPath \ "primary-id").readNullable[String] ~
(JsPath \ "related-account-id").readNullable[String]
) (Msisdn.apply _)
}
第三次使用 new Format
。在这种情况下,您可以使用 json 对象,并检查该字段是否存在。
还有一个方法,忘记怎么做了。它的使用方式 fmap
,可能。
对不起我的英语。
没有 flatten annotation 可用,但遵守规则更容易。
import play.api.libs.json._
case class MsisdnMeta(relatedAccountId: Option[String])
object MsisdnMeta {
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming { _ => "related-account-id" })
implicit val format: OFormat[MsisdnMeta] = Json.format
}
case class Msisdn(
primaryId: Option[String],
meta: Option[MsisdnMeta]) {
@inline def relatedAccountId: Option[String] =
meta.flatMap(_.relatedAccountId)
}
object Msisdn {
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming {
case "primaryId" => "primary-id"
case _ => "meta"
})
implicit val format: OFormat[Msisdn] = Json.format
}
然后reading/parsing JSON:
val json = Json.parse("""{
"valid-for-start-datetime": "2019-08-23T10:47:17.485Z",
"primary-id": "393823468684",
"meta": {
"related-account-id": "10001771",
"roles": [
"customer"
]
}
}""")
val res = json.validate[Msisdn]
// play.api.libs.json.JsResult[Msisdn] = JsSuccess(Msisdn(Some(393823468684),Some(MsisdnMeta(Some(10001771)))),)
res.foreach { suc =>
println(s"relatedAccountId = ${suc.relatedAccountId}")
}
// relatedAccountId = Some(10001771)
... 并写入 JSON:
Json.toJson(Msisdn(Some("id"), Some(MsisdnMeta(Some("bar")))))
// play.api.libs.json.JsValue = {"primary-id":"id","meta":{"related-account-id":"bar"}}
通过将一些工厂添加到伴随对象,使用嵌套元创建 Msisdn
会更容易。
object Msisdn {
// Added factory
@inline def apply(
primaryId: Option[String],
relatedAccountId: String): Msisdn =
Msisdn(primaryId, Some(MsisdnMeta(Some(relatedAccountId))))
private implicit val jsonConfiguration: JsonConfiguration =
JsonConfiguration(JsonNaming {
case "primaryId" => "primary-id"
case _ => "meta"
})
implicit val format: OFormat[Msisdn] = Json.format
}
Json.toJson(Msisdn(Some("id"), "bar"))
// play.api.libs.json.JsValue = {"primary-id":"id","meta":{"related-account-id":"bar"}}