【问题标题】:Adding a JSON field to a Scala case class将 JSON 字段添加到 Scala 案例类
【发布时间】:2016-02-10 19:55:34
【问题描述】:

我有一个 Scala 案例类

case class NumericParam(minValue: Option[Int] = None,
                        maxValue: Option[Int] = None,
                        decimalPlaces: Option[Int] = None,
                        signed: Option[Boolean] = None,
                        hintText: Option[String] = None)

及其伴随对象,我在其中定义了一个隐式 writes 方法

object NumericParam {
    implicit val writes = new Writes[NumericParam] {
        override def writes(value: NumericParam): JsValue = {
          Json.obj(
            "dataType" -> "Numeric",
            "minValue" -> value.maxValue,
            "maxValue" -> value.maxValue,
            "decimalPlaces" -> value.decimalPlaces,
            "signed" -> value.signed,
            "hintText" -> value.hintText
          )
        }
    }
}

我正在添加字段dataType。有没有办法使用宏派生的Writes 值(来自Json.writes[NumericParam])并添加额外的dataType 字段?

【问题讨论】:

    标签: json scala playframework


    【解决方案1】:

    您可以使用Writes#transform 来执行此操作。一种方法是使用函数JsValue => JsValue。安全的方法:

    implicit val writes = Json.writes[NumericParam] transform { js =>
      js match {
        case obj: JsObject => obj + ("dataType" -> JsString("Numeric"))
        case _ => js
      }
    }
    

    但是,我们确实知道js 应该始终JsObject,因为我们正在对特定类型进行操作,因此我们可以缩短它。

    implicit val writes = Json.writes[NumericParam]
       .transform(_.as[JsObject] + ("dataType" -> JsString("Numeric")))
    

    例子:

    scala> val num = NumericParam(Some(1), Some(10), Some(2), Some(false), Some("test"))
    num: NumericParam = NumericParam(Some(1),Some(10),Some(2),Some(false),Some(test))
    
    scala> Json.toJson(num)
    res5: play.api.libs.json.JsValue = {"minValue":1,"maxValue":10,"decimalPlaces":2,"signed":false,"hintText":"test","dataType":"Numeric"}
    

    为了使上述更安全通用,我们可以使用一些隐式魔法来扩展OWrites(它总是写入JsObject)。

    implicit class OWritesExt[A](owrites: OWrites[A]) {
    
      /** Add a (key, value) pair to the JSON object,
       *  where the value is constant.
       */
      def withConstant[B : Writes](key: String, value: B): OWrites[A] = 
        withValue(key, _ => value)
    
      /** Add a key, value pair to the JSON object that is written, where
       *  the value depends on the original object.
       */
      def withValue[B : Writes](key: String, value: A => B): OWrites[A] = 
        new OWrites[A] {
          def writes(a: A): JsObject = owrites.writes(a) ++ Json.obj(key -> value(a))
        }
    
    }
    

    用法:

    implicit val writes = Json.writes[NumericParam]
        .withValue("type", _.getClass.toString)
        .withConstant("other", "something")
    
    scala> Json.toJson(NumericParam(Some(1)))
    res6: play.api.libs.json.JsValue = {"minValue":1,"type":"class NumericParam","other":"something"}
    

    现在您可以废弃一些原始样板,并将这样的调用链接在一起。现在我只是想知道为什么我一直没有这样做。

    【讨论】:

    • 这就是我想要的。我认为它会涉及transform,但无法弄清楚如何。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2016-09-07
    • 2016-01-13
    • 2020-08-12
    • 1970-01-01
    • 2018-03-16
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多