为扩展特征的类获取Play JSON JsValueWrapper [英] Getting a Play JSON JsValueWrapper for a class that extends a trait

查看:159
本文介绍了为扩展特征的类获取Play JSON JsValueWrapper的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为速度生成JSON,其中单位可能会有所不同.我有一个SpeedUnit特性和扩展它的类(结,MetersPerSecond,MilesPerHour). JSON Play文档说:要将自己的模型转换为JsValues,必须定义隐式写入转换器并在范围内提供它们."我在大多数地方都可以使用它,但是当我上一堂延伸特质的课程时却无法使用.我究竟做错了什么?还是有我应该或应该使用的Enum变体?

I'm generating JSON for a speed where the units may vary. I have a SpeedUnit trait and classes that extend it (Knots, MetersPerSecond, MilesPerHour). The JSON Play documentation said "To convert your own models to JsValues, you must define implicit Writes converters and provide them in scope." I got that to work in most places but not when I had a class extending a trait. What am I doing wrong? Or is there an Enum variant I could or should have used instead?

// Type mismatch: found (String, SpeedUnit), required (String, Json.JsValueWrapper)
// at 4th line from bottom:  "speedunit" -> unit

import play.api.libs.json._

trait SpeedUnit {
  // I added this to SpeedUnit thinking it might help, but it didn't.
  implicit val speedUnitWrites = new Writes[SpeedUnit] {
    def writes(x: SpeedUnit) = Json.toJson("UnspecifiedSpeedUnit")
  }
}

class Knots extends SpeedUnit {
  implicit val knotsWrites = new Writes[Knots] {
    def writes(x: Knots) = Json.toJson("KT")
  }
}
class MetersPerSecond extends SpeedUnit {
  implicit val metersPerSecondWrites = new Writes[MetersPerSecond] {
    def writes(x: MetersPerSecond) = Json.toJson("MPS")
  }
}
class MilesPerHour extends SpeedUnit {
  implicit val milesPerHourWrites = new Writes[MilesPerHour] {
    def writes(x: MilesPerHour) = Json.toJson("MPH")
  }
}

// ...

class Speed(val value: Int, val unit: SpeedUnit) {
  implicit val speedWrites = new Writes[Speed] {
    def writes(x: Speed) = Json.obj(
      "value" -> value,
      "speedUnit" -> unit  // THIS LINE DOES NOT TYPE-CHECK
    )
  }
}

推荐答案

Writes是类型类的示例,这意味着对于给定的A,您需要一个Writes[A]的单个实例,而不是每个A实例.如果您来自Java背景,请考虑使用Comparator而不是Comparable.

Writes is an example of a type class, which means you need a single instance of a Writes[A] for a given A, not for every A instance. If you're coming from a Java background, think Comparator instead of Comparable.

import play.api.libs.json._

sealed trait SpeedUnit
case object Knots extends SpeedUnit
case object MetersPerSecond extends SpeedUnit
case object MilesPerHour extends SpeedUnit

object SpeedUnit {
  implicit val speedUnitWrites: Writes[SpeedUnit] = new Writes[SpeedUnit] {
    def writes(x: SpeedUnit) = Json.toJson(
      x match {
        case Knots => "KTS"
        case MetersPerSecond => "MPS"
        case MilesPerHour => "MPH"
      }
    )
  }
}

case class Speed(value: Int, unit: SpeedUnit)

object Speed {
  implicit val speedWrites: Writes[Speed] = new Writes[Speed] {
    def writes(x: Speed) = Json.obj(
      "value" -> x.value,
      "speedUnit" -> x.unit
    )
  }
}

然后:

scala> Json.toJson(Speed(10, MilesPerHour))
res0: play.api.libs.json.JsValue = {"value":10,"speedUnit":"MPH"}

我已经将Writes实例放置在这两种类型的伴随对象中,但是它们可以在其他地方使用(例如,如果您不想在模型中混淆序列化问题).

I've put the Writes instances in the companion objects for the two types, but they can go elsewhere (if you don't want to mix up serialization concerns in your model, for example).

您还可以使用Play JSON的功能API来简化(或至少简明扼要)这一点:

You can also simplify (or at least concise-ify) this a lot with Play JSON's functional API:

sealed trait SpeedUnit
case object Knots extends SpeedUnit
case object MetersPerSecond extends SpeedUnit
case object MilesPerHour extends SpeedUnit

case class Speed(value: Int, unit: SpeedUnit)

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val speedWrites: Writes[Speed] = (
  (__ \ 'value).write[Int] and
  (__ \ 'speedUnit).write[String].contramap[SpeedUnit] {
    case Knots => "KTS"
    case MetersPerSecond => "MPS"
    case MilesPerHour => "MPH"
  }
)(unlift(Speed.unapply))

您采用哪种方法(实用或显式)很大程度上取决于品味.

Which approach you take (functional or explicit) is largely a matter of taste.

这篇关于为扩展特征的类获取Play JSON JsValueWrapper的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆