Scala Play Json - 如何从数组中的元素中读取单个元素?
Scala Play Json - how to read a single element from a element in an Array?
我有这个 json 对象
val jsonObject = """
{
"name" : "camara",
"project" : {
"key" : "DOC",
"name" : "Dockerfiles"
},
"cloneUrl" : "https://server/scm/doc/camara.git",
"links" : {
"clone" : [ {
"href" : "https://server/scm/doc/camara.git",
"name" : "http"
}, {
"href" : "ssh://git@server:7999/doc/camara.git",
"name" : "ssh"
} ],
"self" : [ {
"href" : "url1"
},
{
"href" : "url2"
} ]
}
}
"""
在这种情况下 class 和 Reader:
case class Project(name: String, project: String, projectUrl: List[String])
implicit val projectReader: Reads[Project] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
(JsPath \ "links" \ "self" \ "href").read[List[String]])(Project.apply _)
我尝试解析这个模型:
Json.parse(jsonObject).validate[Project] match {
case value: JsSuccess[Project] =>
println(" >> " + value.get)
case error: JsError =>
println(error)
}
我得到这个错误
JsError(List((/links/self//href,List(ValidationError(error.path.result.multiple,WrappedArray())))))
我不知道如何将这些 href 从 self 数组提取到项目 class 中,看起来像这样:
Project(camara,Dockerfiles,List(url1, url2))
我在互联网上到处寻找可以帮助我走上正轨的简单示例,但我还没有找到任何有用的东西。
如何在不更改项目 class 结构的情况下解决此问题?
import play.api.libs.json._
import play.api.libs.functional.syntax._
val jsonObject = """
{
"name" : "camara",
"project" : {
"key" : "DOC",
"name" : "Dockerfiles"
},
"cloneUrl" : "https://server/scm/doc/camara.git",
"links" : {
"clone" : [ {
"href" : "https://server/scm/doc/camara.git",
"name" : "http"
}, {
"href" : "ssh://git@server:7999/doc/camara.git",
"name" : "ssh"
} ],
"self" : [ {
"href" : "url1"
},
{
"href" : "url2"
} ]
}
}
"""
case class Project(name: String, project: String, projectUrl: List[String])
def multiUrls[T](implicit rt: Reads[T]) = Reads[List[T]] { js =>
val l: List[JsValue] = (__ \ "links" \ "self" \ "href")(js)
Json.fromJson[List[T]](JsArray(l))
}
implicit val projectReader: Reads[Project] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
multiUrls[String])(Project.apply _)
Json.parse(jsonObject).validate[Project] match {
case value: JsSuccess[Project] =>
" >> " + value.get
case error: JsError =>
error.toString
}
// >> Project(camara,Dockerfiles,List(url1, url2))
在你的案例中,JSON 对象的结构没有映射 1:1 到案例 class 上:在 "self" 下面有另一个对象("href" 属性), 但在你的案例中缺少这个级别 class.
因此您可以修改 JSON 数据或案例 class。
如果你想保留两者,你可以解析成"parse only" case class,解析后将这个转换成"target" case class:
case class Url(href: String)
case class ParseProject0(
name: String,
project: String,
projectUrl: List[Url]) {
def toProject: Project = {
Project(name, project, projectUrl.map(_.href))
}
}
implicit val urlReader: Reads[Url] = (
(JsPath \ "href").read[String].map(v => Url(v)))
implicit val projectReader: Reads[ParseProject] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
(JsPath \ "links" \ "self").read[List[Url]])(ParseProject.apply _)
val parsed = Json.parse(jsonObject)
val result = parsed.validate[ParseProject] match {
case value: JsSuccess[ParseProject] =>
val p = value.get.toProject
p
case error: JsError =>
error
}
无论如何,在你的 JSON 对象中查看你的 "clone" 属性,看来你仍然需要额外的 class Url
,因为对象包含多个 属性.
我有这个 json 对象
val jsonObject = """
{
"name" : "camara",
"project" : {
"key" : "DOC",
"name" : "Dockerfiles"
},
"cloneUrl" : "https://server/scm/doc/camara.git",
"links" : {
"clone" : [ {
"href" : "https://server/scm/doc/camara.git",
"name" : "http"
}, {
"href" : "ssh://git@server:7999/doc/camara.git",
"name" : "ssh"
} ],
"self" : [ {
"href" : "url1"
},
{
"href" : "url2"
} ]
}
}
"""
在这种情况下 class 和 Reader:
case class Project(name: String, project: String, projectUrl: List[String])
implicit val projectReader: Reads[Project] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
(JsPath \ "links" \ "self" \ "href").read[List[String]])(Project.apply _)
我尝试解析这个模型:
Json.parse(jsonObject).validate[Project] match {
case value: JsSuccess[Project] =>
println(" >> " + value.get)
case error: JsError =>
println(error)
}
我得到这个错误
JsError(List((/links/self//href,List(ValidationError(error.path.result.multiple,WrappedArray())))))
我不知道如何将这些 href 从 self 数组提取到项目 class 中,看起来像这样:
Project(camara,Dockerfiles,List(url1, url2))
我在互联网上到处寻找可以帮助我走上正轨的简单示例,但我还没有找到任何有用的东西。
如何在不更改项目 class 结构的情况下解决此问题?
import play.api.libs.json._
import play.api.libs.functional.syntax._
val jsonObject = """
{
"name" : "camara",
"project" : {
"key" : "DOC",
"name" : "Dockerfiles"
},
"cloneUrl" : "https://server/scm/doc/camara.git",
"links" : {
"clone" : [ {
"href" : "https://server/scm/doc/camara.git",
"name" : "http"
}, {
"href" : "ssh://git@server:7999/doc/camara.git",
"name" : "ssh"
} ],
"self" : [ {
"href" : "url1"
},
{
"href" : "url2"
} ]
}
}
"""
case class Project(name: String, project: String, projectUrl: List[String])
def multiUrls[T](implicit rt: Reads[T]) = Reads[List[T]] { js =>
val l: List[JsValue] = (__ \ "links" \ "self" \ "href")(js)
Json.fromJson[List[T]](JsArray(l))
}
implicit val projectReader: Reads[Project] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
multiUrls[String])(Project.apply _)
Json.parse(jsonObject).validate[Project] match {
case value: JsSuccess[Project] =>
" >> " + value.get
case error: JsError =>
error.toString
}
// >> Project(camara,Dockerfiles,List(url1, url2))
在你的案例中,JSON 对象的结构没有映射 1:1 到案例 class 上:在 "self" 下面有另一个对象("href" 属性), 但在你的案例中缺少这个级别 class.
因此您可以修改 JSON 数据或案例 class。
如果你想保留两者,你可以解析成"parse only" case class,解析后将这个转换成"target" case class:
case class Url(href: String)
case class ParseProject0(
name: String,
project: String,
projectUrl: List[Url]) {
def toProject: Project = {
Project(name, project, projectUrl.map(_.href))
}
}
implicit val urlReader: Reads[Url] = (
(JsPath \ "href").read[String].map(v => Url(v)))
implicit val projectReader: Reads[ParseProject] = (
(JsPath \ "name").read[String] and
(JsPath \ "project" \ "name").read[String] and
(JsPath \ "links" \ "self").read[List[Url]])(ParseProject.apply _)
val parsed = Json.parse(jsonObject)
val result = parsed.validate[ParseProject] match {
case value: JsSuccess[ParseProject] =>
val p = value.get.toProject
p
case error: JsError =>
error
}
无论如何,在你的 JSON 对象中查看你的 "clone" 属性,看来你仍然需要额外的 class Url
,因为对象包含多个 属性.