如何在Scala Play框架中将trait和对象解析为JSON
目前我正在使用Play框架开发一个web应用程序,现在我正在开发一个JSON api。不幸的是,我在使用内置JSON库将对象解析为JSON时遇到问题。我们有以下特性,它定义了装运的类型和要使用的解析器。还有一个case类,它有一个ShipmentType,所以我们知道每个类型使用哪个解析器。还有一种方法可以将所有存储的货物作为列表返回如何在Scala Play框架中将trait和对象解析为JSON,json,scala,playframework,Json,Scala,Playframework,目前我正在使用Play框架开发一个web应用程序,现在我正在开发一个JSON api。不幸的是,我在使用内置JSON库将对象解析为JSON时遇到问题。我们有以下特性,它定义了装运的类型和要使用的解析器。还有一个case类,它有一个ShipmentType,所以我们知道每个类型使用哪个解析器。还有一种方法可以将所有存储的货物作为列表返回 trait ShipmentType { def parser(list: List[String]): ShipmentTypeParser } ob
trait ShipmentType {
def parser(list: List[String]): ShipmentTypeParser
}
object ShipmentTypeA extends ShipmentType {
def parser(list: List[String]) = new ShipmentTypeAParser(list)
}
object ShipmentTypeB extends ShipmentType {
def parser(list: List[String]) = new ShipmentTypeBParser(list)
}
object ShipmentTypeC extends ShipmentType {
def parser(list: List[String]) = new ShipmentTypeCParser(list)
}
case class Shipment(id: Long, name: String, date: Date, shipmentType: Type)
要编写此JSON,我使用以下隐式val:
import play.api.libs.json._
import play.api.libs.functional.syntax._
def findAll = Action {
Ok(Json.toJson(Shipments.all))
}
implicit val shipmentWrites: Writes[Shipment] = (
(JsPath \ "id").write[Option[Long]] and
(JsPath \ "name").write[String] and
(JsPath \ "date").write[Date] and
(JsPath \ "shipmentType").write[ShipmentType]
)(unlift(Shipment.unapply))
接下来,我们需要一个额外的ShipmentType:
implicit val shipmentTypeWriter: Writes[ShipmentType] = ()
但是我遇到了一些问题,我似乎找不到一种方法来定义ShipmentType的编写器
根据Play Framework文档的另一页,我还尝试将它们定义如下:
implicit val shipmentWrites: Writes[Shipment] = Json.writes[Shipment]
implicit val shipmentTypeWrites: Writes[ShipmentType] =Json.writes[ShipmentType]
然而,这也失败了,因为我得到了错误,比如:“没有找到unapply函数”。
有人想知道如何实现这方面的编写器吗?最好是json格式的字符串。我创建了一个工作示例:
并在scalatest中进行测试:
trait ShipmentTypeParser
class ShipmentTypeAParser(list: List[String]) extends ShipmentTypeParser
class ShipmentTypeBParser(list: List[String]) extends ShipmentTypeParser
object ShipmentTypeA extends ShipmentType {
override def parser(list: List[String]) = new ShipmentTypeAParser(list)
}
object ShipmentTypeB extends ShipmentType {
override def parser(list: List[String]) = new ShipmentTypeBParser(list)
}
object Models {
implicit val shipmentTypeWrites = new Format[ShipmentType] {
override def writes(shipmentType: ShipmentType): JsValue =
JsString(shipmentType.getClass.getName)
override def reads(json: JsValue): JsResult[ShipmentType] = json match {
case JsString(className) =>
Try(Class.forName(className)) match {
case Success(c) =>
JsSuccess(c.getField("MODULE$").get(c).asInstanceOf[ShipmentType])
case Failure(th) =>
JsError(th.getMessage)
}
case _ =>
JsError(json.toString)
}
}
implicit val shipmentWrites: Format[Shipment] = Json.format[Shipment]
}
trait ShipmentType {
def parser(list: List[String]): ShipmentTypeParser
}
case class Shipment(id: Long, name: String, date: Date, shipmentType: ShipmentType)
class JsonSpec extends FlatSpec with Matchers {
"Shipment " should " be convert to json and from " in {
import Models._
val shipment = Shipment(3, "33", new Date(), ShipmentTypeA)
val jsonShipment = Json.toJson(shipment)
println(jsonShipment)
val fromJson = Json.fromJson[Shipment](jsonShipment)
fromJson match{
case JsSuccess(shipmentFromJson,_) =>
shipmentFromJson shouldBe shipment
case _ =>
fail(fromJson.toString)
}
}
}