简体   繁体   English

播放2.4参数化代数数据类型JSON验证

[英]Play 2.4 parameterized algebraic data types JSON validation

Is it possible to do something like that in Scala / Play 2.4: 是否有可能在Scala / Play 2.4中做类似的事情:

sealed trait Location { val `type`: String }
case class CityLocation(zip_code: String, override val `type`: String = "city") extends Location
case class AddressLocation(
  society: Option[String],
  first_name: String,
  last_name: String,
  ...
  override val `type`: String = "address"
) extends Location

sealed trait Point[T <: Location] { val `type`: String; val location: T }
case class ShippingPoint[T](override val location: T, override val `type`: String = "shipping") extends Point[T]
case class PickupPoint[T](override val location: T, override val `type`: String = "pickup") extends Point[T]

object CityLocation {
  implicit val format = Json.format[CityLocation]
}
object AddressLocation {
  implicit val format = Json.format[AddressLocation]
}
object ShippingPoint {
  implicit def write[T] = Json.writes[ShippingPoint[T]]
  implicit def read[T]: Reads[ShippingPoint[T]] = (
    (__ \ "location").read[T] and
      (__ \ "type").read[String](exactWordRead("shipping", "error.route.shipping.type"))
  )(ShippingPoint[T].apply _)
}
object PickupPoint {
  implicit def write[T] = Json.writes[ShippingPoint[T]]
  implicit def read[T]: Reads[PickupPoint[T]] = (
    (__ \ "location").read[T] and
      (__ \ "type").read[String](exactWordRead("pickup", "error.route.pickup.type"))
  )(PickupPoint[T].apply _)
}

?? ??

For now, It does not compile. 目前,它没有编译。

The exactWordRead method is defined as follow : exactWordRead方法定义如下:

def exactWordRead(word: String, errorMessage: String): Reads[String] = Reads.constraints.pattern(s"^$word${"$"}".r, errorMessage)

Edit : 编辑

It seems that I maid a step forward thanks to this answer https://stackoverflow.com/a/29834113/2431728 : 由于这个答案https://stackoverflow.com/a/29834113/2431728 ,我似乎向前迈了一步:

sealed trait Location { val `type`: String }
case class CityLocation(zip_code: String, override val `type`: String = "city") extends Location
case class AddressLocation(
  society: Option[String],
  first_name: String,
  last_name: String,
  ...
  override val `type`: String = "address"
) extends Location

sealed trait Point[T <: Location] { val location: T; val `type`: String }
case class ShippingPoint[T](override val location: T, override val `type`: String = "shipping") extends Point[T]
case class PickupPoint[T](override val location: T, override val `type`: String = "pickup") extends Point[T]

object CityLocation {
  implicit val format = Json.format[CityLocation]
}
object AddressLocation {
  implicit val format = Json.format[AddressLocation]
}
object ShippingPoint {
  implicit def format[T: Format]: Format[ShippingPoint[T]] = (
    (__ \ "location").format[T] and
      (__ \ "type").format[String](exactWordRead("shipping", "error.route.shipping.type"))
  )(ShippingPoint.apply, unlift(ShippingPoint.unapply))
}
object PickupPoint {
  implicit def format[T: Format]: Format[PickupPoint[T]] = (
    (__ \ "location").format[T] and
      (__ \ "type").format[String](exactWordRead("pickup", "error.route.pickup.type"))
  )(PickupPoint.apply, unlift(PickupPoint.unapply))
}

However, I doesn't compile yet. 但是,我还没编译。 The compile error is : 编译错误是:

[error] type arguments [T] do not conform to trait Point's type parameter bounds [T <: services.coliswebApi.data.Location]
[error] case class ShippingPoint[T](override val location: T, override val `type`: String = "shipping") extends Point[T]
[error]                                                                                                         ^
[error] type arguments [T] do not conform to trait Point's type parameter bounds [T <: services.coliswebApi.data.Location]
[error] case class PickupPoint[T](override val location: T, override val `type`: String = "pickup") extends Point[T]

As said by the compiler, on one side you have, 正如编译器所说,你有一方面,

sealed trait Point[T <: Location]

... and on the other side, ......而在另一边,

case class ShippingPoint[T](???) extends Point[T]
case class PickupPoint[T](???) extends Point[T]

But nothing in the declarations of ShippingPoint and PickupPoint is proving the type parameter is compatible with the constraint <: Location , required to extend Point . 但是, ShippingPointPickupPoint的声明中没有任何内容证明type参数与约束<: Location兼容,需要扩展Point

So you need to fix that. 所以你需要解决这个问题。

case class ShippingPoint[T <: Location](???) extends Point[T]
case class PickupPoint[T <: Location](???) extends Point[T]

I think you also need to bound your type in your format like this 我认为你还需要以这样的格式绑定你的类型

implicit def format[T <: Location: Format]: Format[ShippingPoint[T]] = (
        (__ \ "location").format[T] and
        (__ \ "type").format[String](exactWordRead("shipping",   "error.route.shipping.type"))
    )(ShippingPoint.apply, unlift(ShippingPoint.unapply))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM