如何在 play.api.libs.json.JsValue 和 org.json4s.JValue 之间转换
How can I convert between play.api.libs.json.JsValue and org.json4s.JValue
我正在使用 Play Framework 构建一个 API,但需要使用仅支持 Json4s 的库执行一些验证和转换操作。
到目前为止,我唯一能够开始工作的是转换为字符串并使用目标库进行解析:
import org.json4s._
import org.json4s.jackson.JsonMethods._
import play.api.libs.json._
val playJson: JsValue = Json.parse(compact(render(json4sJson)))
val json4sJson: JValue = parse(Json.stringify(playJson))
但这显然效率低下并且会导致代码难看。有没有更好的方法?
模式匹配和转换
写入从一个到另一个的隐式转换。
模式匹配和转换
JsString 到 JString
JsNull 到 JNull
JsNumber 到 JNumber
JsArray 到 JArray ... 等等
使用 Intellij 的 ALT + ENTER 功能(如果您正在使用它)自动获取所有案例对象和案例 class 进行模式匹配(无需手动检查源代码)。
如果是JsArray和JsObject则递归转换成JArray和JObject对应
import play.api.libs.{ json => pjson }
import org.{ json4s => j4s }
object Conversions {
implicit def toJson4s(json: play.api.libs.json.JsValue):org.json4s.JValue = json match {
case pjson.JsString(str) => j4s.JString(str)
case pjson.JsNull => j4s.JNull
case pjson.JsBoolean(value) => j4s.JBool(value)
case pjson.JsNumber(value) => j4s.JDecimal(value)
case pjson.JsArray(items) => j4s.JArray(items.map(toJson4s(_)).toList)
case pjson.JsObject(items) => j4s.JObject(items.map { case (k, v) => k -> toJson4s(v)}.toList)
}
implicit def toPlayJson(json: org.json4s.JValue): play.api.libs.json.JsValue = json match {
case j4s.JString(str) => pjson.JsString(str)
case j4s.JNothing => pjson.JsNull
case j4s.JNull => pjson.JsNull
case j4s.JDecimal(value) => pjson.JsNumber(value)
case j4s.JDouble(value) => pjson.JsNumber(value)
case j4s.JInt(value) => pjson.JsNumber(BigDecimal(value))
case j4s.JLong(value) => pjson.JsNumber(BigDecimal(value))
case j4s.JBool(value) => pjson.JsBoolean(value)
case j4s.JSet(fields) => pjson.JsArray(fields.toList.map(toPlayJson(_)))
case j4s.JArray(fields) => pjson.JsArray(fields.map(toPlayJson(_)))
case j4s.JObject(fields) => pjson.JsObject(fields.map { case (k, v) => k -> toPlayJson(v)}.toMap)
}
}
当您想将一个转换为另一个时,只需导入转换对象
import Conversions._
Scala REPL
scala> object Conversions {
|
| implicit def toJson4s(json: play.api.libs.json.JsValue):org.json4s.JValue = json match {
| case pjson.JsString(str) => j4s.JString(str)
| case pjson.JsNull => j4s.JNull
| case pjson.JsBoolean(value) => j4s.JBool(value)
| case pjson.JsNumber(value) => j4s.JDecimal(value)
| case pjson.JsArray(items) => j4s.JArray(items.map(toJson4s(_)).toList)
| case pjson.JsObject(items) => j4s.JObject(items.map { case (k, v) => k -> toJson4s(v)}.toList)
| }
|
| implicit def toPlayJson(json: org.json4s.JValue): play.api.libs.json.JsValue = json match {
| case j4s.JString(str) => pjson.JsString(str)
| case j4s.JNothing => pjson.JsNull
| case j4s.JNull => pjson.JsNull
| case j4s.JDecimal(value) => pjson.JsNumber(value)
| case j4s.JDouble(value) => pjson.JsNumber(value)
| case j4s.JInt(value) => pjson.JsNumber(BigDecimal(value))
| case j4s.JLong(value) => pjson.JsNumber(BigDecimal(value))
| case j4s.JBool(value) => pjson.JsBoolean(value)
| case j4s.JArray(fields) => pjson.JsArray(fields.map(toPlayJson(_)))
| case j4s.JObject(fields) => pjson.JsObject(fields.map { case (k, v) => k -> toPlayJson(v)}.toMap)
| }
|
| }
warning: there were two feature warnings; re-run with -feature for details
defined object Conversions
scala> import Conversions._
import Conversions._
scala> val json = pjson.Json.parse("""{"name": "pamu", "age": 1}""")
json: play.api.libs.json.JsValue = {"name":"pamu","age":1}
scala> toJson4s(json)
res0: org.json4s.JValue = JObject(List((name,JString(pamu)), (age,JDecimal(1))))
更多嵌套Json
scala> val payload = pjson.Json.parse("""
| {
| "firstName": "John",
| "lastName": "Smith",
| "isAlive": true,
| "age": 25,
| "address": {
| "streetAddress": "21 2nd Street",
| "city": "New York",
| "state": "NY",
| "postalCode": "10021-3100"
| },
| "phoneNumbers": [
| {
| "type": "home",
| "number": "212 555-1234"
| },
| {
| "type": "office",
| "number": "646 555-4567"
| },
| {
| "type": "mobile",
| "number": "123 456-7890"
| }
| ],
| "children": [],
| "spouse": null
| }
| """)
payload: play.api.libs.json.JsValue = {"firstName":"John","lastName":"Smith","isAlive":true,"age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}
scala> toJson4s(payload)
res1: org.json4s.JValue = JObject(List((children,JArray(List())), (isAlive,JBool(true)), (spouse,JNull), (phoneNumbers,JArray(List(JObject(List((type,JString(home)), (number,JString(212 555-1234)))), JObject(List((type,JString(office)), (number,JString(646 555-4567)))), JObject(List((type,JString(mobile)), (number,JString(123 456-7890))))))), (age,JDecimal(25)), (lastName,JString(Smith)), (firstName,JString(John)), (address,JObject(List((streetAddress,JString(21 2nd Street)), (city,JString(New York)), (state,JString(NY)), (postalCode,JString(10021-3100)))))))
我正在使用 Play Framework 构建一个 API,但需要使用仅支持 Json4s 的库执行一些验证和转换操作。
到目前为止,我唯一能够开始工作的是转换为字符串并使用目标库进行解析:
import org.json4s._
import org.json4s.jackson.JsonMethods._
import play.api.libs.json._
val playJson: JsValue = Json.parse(compact(render(json4sJson)))
val json4sJson: JValue = parse(Json.stringify(playJson))
但这显然效率低下并且会导致代码难看。有没有更好的方法?
模式匹配和转换
写入从一个到另一个的隐式转换。
模式匹配和转换
JsString 到 JString
JsNull 到 JNull
JsNumber 到 JNumber
JsArray 到 JArray ... 等等
使用 Intellij 的 ALT + ENTER 功能(如果您正在使用它)自动获取所有案例对象和案例 class 进行模式匹配(无需手动检查源代码)。
如果是JsArray和JsObject则递归转换成JArray和JObject对应
import play.api.libs.{ json => pjson }
import org.{ json4s => j4s }
object Conversions {
implicit def toJson4s(json: play.api.libs.json.JsValue):org.json4s.JValue = json match {
case pjson.JsString(str) => j4s.JString(str)
case pjson.JsNull => j4s.JNull
case pjson.JsBoolean(value) => j4s.JBool(value)
case pjson.JsNumber(value) => j4s.JDecimal(value)
case pjson.JsArray(items) => j4s.JArray(items.map(toJson4s(_)).toList)
case pjson.JsObject(items) => j4s.JObject(items.map { case (k, v) => k -> toJson4s(v)}.toList)
}
implicit def toPlayJson(json: org.json4s.JValue): play.api.libs.json.JsValue = json match {
case j4s.JString(str) => pjson.JsString(str)
case j4s.JNothing => pjson.JsNull
case j4s.JNull => pjson.JsNull
case j4s.JDecimal(value) => pjson.JsNumber(value)
case j4s.JDouble(value) => pjson.JsNumber(value)
case j4s.JInt(value) => pjson.JsNumber(BigDecimal(value))
case j4s.JLong(value) => pjson.JsNumber(BigDecimal(value))
case j4s.JBool(value) => pjson.JsBoolean(value)
case j4s.JSet(fields) => pjson.JsArray(fields.toList.map(toPlayJson(_)))
case j4s.JArray(fields) => pjson.JsArray(fields.map(toPlayJson(_)))
case j4s.JObject(fields) => pjson.JsObject(fields.map { case (k, v) => k -> toPlayJson(v)}.toMap)
}
}
当您想将一个转换为另一个时,只需导入转换对象
import Conversions._
Scala REPL
scala> object Conversions {
|
| implicit def toJson4s(json: play.api.libs.json.JsValue):org.json4s.JValue = json match {
| case pjson.JsString(str) => j4s.JString(str)
| case pjson.JsNull => j4s.JNull
| case pjson.JsBoolean(value) => j4s.JBool(value)
| case pjson.JsNumber(value) => j4s.JDecimal(value)
| case pjson.JsArray(items) => j4s.JArray(items.map(toJson4s(_)).toList)
| case pjson.JsObject(items) => j4s.JObject(items.map { case (k, v) => k -> toJson4s(v)}.toList)
| }
|
| implicit def toPlayJson(json: org.json4s.JValue): play.api.libs.json.JsValue = json match {
| case j4s.JString(str) => pjson.JsString(str)
| case j4s.JNothing => pjson.JsNull
| case j4s.JNull => pjson.JsNull
| case j4s.JDecimal(value) => pjson.JsNumber(value)
| case j4s.JDouble(value) => pjson.JsNumber(value)
| case j4s.JInt(value) => pjson.JsNumber(BigDecimal(value))
| case j4s.JLong(value) => pjson.JsNumber(BigDecimal(value))
| case j4s.JBool(value) => pjson.JsBoolean(value)
| case j4s.JArray(fields) => pjson.JsArray(fields.map(toPlayJson(_)))
| case j4s.JObject(fields) => pjson.JsObject(fields.map { case (k, v) => k -> toPlayJson(v)}.toMap)
| }
|
| }
warning: there were two feature warnings; re-run with -feature for details
defined object Conversions
scala> import Conversions._
import Conversions._
scala> val json = pjson.Json.parse("""{"name": "pamu", "age": 1}""")
json: play.api.libs.json.JsValue = {"name":"pamu","age":1}
scala> toJson4s(json)
res0: org.json4s.JValue = JObject(List((name,JString(pamu)), (age,JDecimal(1))))
更多嵌套Json
scala> val payload = pjson.Json.parse("""
| {
| "firstName": "John",
| "lastName": "Smith",
| "isAlive": true,
| "age": 25,
| "address": {
| "streetAddress": "21 2nd Street",
| "city": "New York",
| "state": "NY",
| "postalCode": "10021-3100"
| },
| "phoneNumbers": [
| {
| "type": "home",
| "number": "212 555-1234"
| },
| {
| "type": "office",
| "number": "646 555-4567"
| },
| {
| "type": "mobile",
| "number": "123 456-7890"
| }
| ],
| "children": [],
| "spouse": null
| }
| """)
payload: play.api.libs.json.JsValue = {"firstName":"John","lastName":"Smith","isAlive":true,"age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}
scala> toJson4s(payload)
res1: org.json4s.JValue = JObject(List((children,JArray(List())), (isAlive,JBool(true)), (spouse,JNull), (phoneNumbers,JArray(List(JObject(List((type,JString(home)), (number,JString(212 555-1234)))), JObject(List((type,JString(office)), (number,JString(646 555-4567)))), JObject(List((type,JString(mobile)), (number,JString(123 456-7890))))))), (age,JDecimal(25)), (lastName,JString(Smith)), (firstName,JString(John)), (address,JObject(List((streetAddress,JString(21 2nd Street)), (city,JString(New York)), (state,JString(NY)), (postalCode,JString(10021-3100)))))))