Scala播放:列表到Json数组
我有一个包含一些个性化对象的列表。后者的定义如下:Scala播放:列表到Json数组,json,scala,play-json,Json,Scala,Play Json,我有一个包含一些个性化对象的列表。后者的定义如下: sealed case class Personalization(firstname: String, lastname: String, keycardId: String) "personalization": [ { "id": "firstname", "value": "John" },
sealed case class Personalization(firstname: String, lastname: String, keycardId: String)
"personalization": [
{
"id": "firstname",
"value": "John"
},
{
"id": "lastname",
"value": "Doe"
}...
我需要将此列表映射到Json数组结构,该结构必须如下所示:
sealed case class Personalization(firstname: String, lastname: String, keycardId: String)
"personalization": [
{
"id": "firstname",
"value": "John"
},
{
"id": "lastname",
"value": "Doe"
}...
我正在努力将字段信息映射到id/值对。通常,我会在Personalization类中创建play.api.libs.json.Format,并让它自动映射->json.Format[Personalization]
——但这次,我需要创建一个数组,其中一个条目可以容纳n个属性
因此,我在征求意见,是否有可能使用Scala Play框架?
非常感谢您的任何意见,谢谢 也许我可以用更优雅的方式来做,但您可以使用以下代码片段:
case class Field(id: String, value: String)
object Field {
implicit val fieldFormatter: Format[Field] = Json.format[Field]
}
sealed case class Personalization(firstname: String, lastname: String, keycardId: String)
object Personalization {
implicit val personalizationFormatter: Format[Personalization] = new Format[Personalization] {
override def reads(json: JsValue): JsResult[Personalization] =
Try {
val data = (json \ "personalization").as[JsValue]
data match {
case JsArray(value) =>
val fields = value.map(_.as[Field]).map(f => f.id -> f.value).toMap
val firstname = fields.getOrElse("firstname", throw new IllegalArgumentException("Mandatory field firstname is absent."))
val lastname = fields.getOrElse("lastname", throw new IllegalArgumentException("Mandatory field lastname is absent."))
val keycardId = fields.getOrElse("keycardId", throw new IllegalArgumentException("Mandatory field keycardId is absent."))
Personalization(firstname, lastname, keycardId)
case _ => throw new IllegalArgumentException("Incorrect json format for Personalization.")
}
}.toEither.fold(e => JsError(e.getMessage), JsSuccess(_))
override def writes(o: Personalization): JsValue = {
val fields = List(Field("firstname", o.firstname), Field("lastname", o.lastname), Field("keycardId", o.keycardId))
JsObject(List("personalization" -> Json.toJson(fields)))
}
}
}
它将
{“personalization”:[{“id”:“firstname”,“value”:“John”},{“id”:“lastname”,“value”:“Doe”},{“id”:“keycardId”,“value”:“1234”}]}
转换为个性化(John,Doe,1234)
,反之亦然使用编写JSON表示并不十分复杂
import play.api.libs.json._
case class Personalization(firstname: String, lastname: String, keycardId: String) // No need to seal a case class
implicit def writes: Writes[Personalization] = {
val tx: JsValue => JsValue = {
case JsObject(fields) => Json.toJson(fields.map {
case (k, v) => Json.obj("id" -> k, "value" -> v)
})
case jsUnexpected => jsUnexpected // doesn't happen with OWrites
}
Json.writes[Personalization].transform(tx)
}
可按以下方式进行测试
val personalization = Personalization(
firstname = "First",
lastname = "Last",
keycardId = "Foo")
val jsonRepr = Json.toJson(personalization)
// => [{"id":"firstname","value":"First"},{"id":"lastname","value":"Last"},{"id":"keycardId","value":"Foo"}]
Json.parse("""[
{"id":"firstname","value":"First"},
{"id":"lastname","value":"Last"},
{"id":"keycardId","value":"Foo"}
]""").validate[Personalization]
// => JsSuccess(Personalization(First,Last,Foo),)
阅读有点棘手:
implicit def reads: Reads[Personalization] = {
type Field = (String, Json.JsValueWrapper)
val fieldReads = Reads.seq(Reads[Field] { js =>
for {
id <- (js \ "id").validate[String]
v <- (js \ "value").validate[JsValue]
} yield id -> v
})
val underlying = Json.reads[Personalization]
Reads[Personalization] { js =>
js.validate(fieldReads).flatMap { fields =>
Json.obj(fields: _*).validate(underlying)
}
}
}
注意,is方法可用于任何案例类格式
即使在Try
中也不建议引发异常,特别是当可以使用JsResult
时。最好使用。as