una - obtener valor de json javascript
Obteniendo un juego JSON JsValueWrapper para una clase que extiende un rasgo (1)
Writes
es un ejemplo de una clase de tipo, lo que significa que necesita una instancia única de una Writes[A]
para una A
determinada, no para cada instancia A
Si proviene de un fondo Java, piense en Comparator
lugar de 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
)
}
}
Y entonces:
scala> Json.toJson(Speed(10, MilesPerHour))
res0: play.api.libs.json.JsValue = {"value":10,"speedUnit":"MPH"}
Puse las instancias de Writes
en los objetos complementarios para los dos tipos, pero pueden ir a otra parte (por ejemplo, si no desea mezclar problemas de serialización en su modelo).
También puedes simplificar (o al menos conciso) mucho con la API funcional de Play JSON:
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))
El enfoque que tome (funcional o explícito) es en gran parte una cuestión de gusto.
Estoy generando JSON para una velocidad donde las unidades pueden variar. Tengo un rasgo SpeedUnit y clases que lo extienden (Knots, MetersPerSecond, MilesPerHour). La documentación de JSON Play decía: "Para convertir sus propios modelos en JsValues, debe definir convertidores Writes implícitos y proporcionarlos en el alcance". Lo conseguí para trabajar en la mayoría de los lugares pero no cuando tenía una clase que extendía un rasgo. ¿Qué estoy haciendo mal? ¿O hay una variante de Enum que podría o debería haber usado en su lugar?
// 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
)
}
}