在软件开发过程中,使用JSON是非常常见的任务。 在Scala中,您可以通过多种方式来做到这一点,或者借助Java流行的库(例如Jackson)或使用Scala特定的库。 如何从Spray JSON, Play JSON ,Argonaut,Jackson,Rapture等中做出正确选择?
有一天,我接受了一次面试的测试任务。 根据它,我必须在电子商务环境中实现Checkout对象的JSON序列化和反序列化。 我分析了Scala的所有现有JSON库,并已将它们用作小样本,并决定采用Play JSON库进行此任务。 我这样做是因为它具有全面的文档和许多示例,它是最受欢迎的Scala Web框架的一部分,并且我喜欢它的API。
问题是如何在没有整个框架的情况下使用PlayFramework JSON模块。 而且我发现了一个单独的git仓库,其中包含完全使用Play JSON API。
对于那些想了解如何与Play Framework分开使用Play JSON模块的人,我继续阅读该文章。
如何使用Play JSON模块?
首先,您需要将Play JSON库添加到您的项目中。 您可以通过多种方式进行操作–下载lib的代码并将其包含在项目中,或使用某些依赖项管理工具。 我个人在Scala项目中使用SBT。
这就是我们可以将Play JSON依赖项添加到SBT文件中的方法:
name := "proectj-name"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies ++= Seq("com.typesafe.play" % "play-json_2.11" % "2.4.2")
然后,您可能想看看如何使用此库执行JSON序列化和反序列化。 好吧,让我们做一个简短的演示。 这是JSON模型,我们需要使用它:
{
"id": 1,
"type": "credit card",
"address": {
"address1": "Baker str 3",
"address2": "",
"city": "London",
"zipcode": "WC064"
},
"token": "u4lPaa74M"
"cvv": 112
}
这是Checkout模型的一部分-付款。 首先,我们需要做什么才能对该JSON模型实现序列化和反序列化?
- 为JSON中最深的模型创建一个Scala模型。 这是“地址”字段的案例类:
case class Address(address1: String, address2: Option[String], city: String, state: String, zipcode: String)
- 声明写入和读取规则,这些规则用于将Scala模型写入JSON以及将JSON读取到Scala。 可以在Address对象中声明此逻辑:
object Address { import play.api.libs.json._ implicit val addressFormats = Json.format[Address] def writeAddress(address: Address) = { Json.toJson(address) } def readAddress(jsonAddress: JsValue) = { jsonAddress.as[Address] } }
如您所见,我们使用Play对象Json ,以执行具有简单字段的对象的序列化和反序列化。 简单来说,我的意思是字符串,数字,数组和空值。
- 对父对象执行操作#1,#2。
case class Payment(id: Long, pType: String, address: Address, token: String, cvv: String) object Payment { import play.api.libs.json._ def writePayment(payment: Payment) = { JsObject(Seq( "id" -> JsNumber(payment.id), "type" -> JsString(payment.pType), "address" -> Json.toJson(payment.address), "token" -> JsString(payment.token), "cvv" -> JsString(payment.cvv) )) } def readPayment(jsonPayment: JsValue) = { val id = (jsonPayment \ "id").as[Long] val pType = (jsonPayment \ "type").as[String] val address = (jsonPayment \ "address").as[Address] val token = (jsonPayment \ "token").as[String] val cvv = (jsonPayment \ "cvv").as[String] Payment(id, pType, address, token, cvv) } }
由于类型字段的名称 ,我们在上面得到了更多详细的代码。 由于类型字在Scala中是保留字,因此我们不能将其用作Scala中变量的名称。 因此,我们必须为“付款”模型定义手动读取和写入。
如何在Scala中测试序列化和序列化?
为了检查一切正常,我们可以创建单元测试。 在SBT文件中添加ScalaTest依赖项。 现在看起来应该像这样:
name := "proectj-name"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies ++= Seq(
"org.scalatest" % "scalatest_2.11" % "3.0.0-SNAP5" % "test",
"com.typesafe.play" % "play-json_2.11" % "2.4.2")
并为付款编写测试:
import models._
import models.Payment._
import org.scalatest._
import play.api.libs.json._
class PaymentTest extends FlatSpec with Matchers {
val address = Address("1375 Burlingame Ave.", None, "Burlingame", "California", "94010")
"Payment " should "be converted to JSON correctly " in {
val payment = Payment(1, "creditCard", address, "wdweadowei3209423", "123")
val paymentJSON = writePayment(payment)
(paymentJSON \ ("id")).get should be (JsNumber(1))
(paymentJSON \ ("type")).get should be (JsString("creditCard"))
(paymentJSON \ ("address")).get should be (Json.toJson(payment.address))
(paymentJSON \ ("token")).get should be (JsString("wdweadowei3209423"))
(paymentJSON \ ("cvv")).get should be (JsString("123"))
}
it should " be deserialized correctly " in {
val paymentJSON: JsValue = JsObject(Seq(
"id" -> JsNumber(1),
"type" -> JsString("creditCard"),
"address" -> Json.toJson(address),
"token" -> JsString("wdweadowei3209423"),
"cvv" -> JsString("123")
))
val payment = readPayment(paymentJSON)
payment.id should be (1)
payment.pType should be ("creditCard")
payment.address should be (address)
payment.token should be ("wdweadowei3209423")
payment.cvv should be ("123")
}
}
摘要
JSON Play模块非常强大。 我没有描述很多可以借助它来完成的事情。 但我建议您阅读官方文档,并在此查看更多示例。 要特别注意您阅读的文档版本和在项目中使用的Scala。
翻译自: https://www.javacodegeeks.com/2015/11/scala-working-with-json.html