【问题标题】:Scala argonaut encode a jEmtpyObject to 'false' rather than 'null'Scala argonaut 将 jEmtpyObject 编码为“false”而不是“null”
【发布时间】:2015-02-18 01:40:18
【问题描述】:

我正在处理我直接控制之外的一些代码,我需要对选项 [Thing] 进行编码,如果 Thing 存在,则情况正常,但是 None 情况必须返回“false”而不是 null。这可以轻松完成吗?我正在查看文档,但没有取得多大成功。

我的代码如下所示:

   case class Thing(name: String)
   case class BiggerThing(stuff: String, thing: Option[Thing])

   implict val ThingEncodeJson: EncodeJson[Thing] =
     EncodeJson(t => ("name" := t.name ) ->: jEmptyObject)

和 BiggerThing 的等价物,json 需要看起来像:

  1. 对于一些人:

    "thing":{"name": "bob"} 
    
  2. 对于无:

    "thing": false
    

但目前 None 情况给出:

"thing":null

如何让它返回 false?有人能指出我正确的方向吗?

干杯

【问题讨论】:

    标签: json scala argonaut


    【解决方案1】:

    您只需要为Option[Thing] 定制一个CodecJson 实例:

    object Example {
      import argonaut._, Argonaut._
    
      case class Thing(name: String)
      case class BiggerThing(stuff: String, thing: Option[Thing])
    
      implicit val encodeThingOption: CodecJson[Option[Thing]] =
        CodecJson(
          (thing: Option[Thing]) => thing.map(_.asJson).getOrElse(jFalse),
          json =>
            // Adopt the easy approach when parsing, that is, if there's no
            // `name` property, assume it was `false` and map it to a `None`.
            json.get[Thing]("name").map(Some(_)) ||| DecodeResult.ok(None)
        )
    
      implicit val encodeThing: CodecJson[Thing] =
        casecodec1(Thing.apply, Thing.unapply)("name")
    
      implicit val encodeBiggerThing: CodecJson[BiggerThing] =
        casecodec2(BiggerThing.apply, BiggerThing.unapply)("stuff", "thing")
    
      def main(args: Array[String]): Unit = {
        val a = BiggerThing("stuff", Some(Thing("name")))
        println(a.asJson.nospaces) // {"stuff":"stuff","thing":{"name":"name"}}
        val b = BiggerThing("stuff", None)
        println(b.asJson.nospaces) // {"stuff":"stuff","thing":false}
      }
    }
    

    thingNone 时,如何对没有thing 属性的BiggerThing 进行编码。那么你需要一个自定义的EncodeJson[BiggerThing] 实例:

    implicit val decodeBiggerThing: DecodeJson[BiggerThing] =
      jdecode2L(BiggerThing.apply)("stuff", "thing")
    
    implicit val encodeBiggerThing: EncodeJson[BiggerThing] =
      EncodeJson { biggerThing =>
        val thing = biggerThing.thing.map(t => Json("thing" := t))
        ("stuff" := biggerThing.stuff) ->: thing.getOrElse(jEmptyObject)
      }
    

    【讨论】:

    • 感谢 Ionut。非常感谢队友。我一直试图将 emptyObject 映射为 jBool(false) 并不断出错。这绝对完美:)而且我现在也学会了如何做到这一点:)
    • 只是出于好奇,你是如何做到的,如果 Thing 不存在,它不会费心尝试将其编码为“name”:null?例如 BiggerThing 会返回 {"stuff":"stuff"}。我会为 BiggerThing 中的每个元素做与上述类似的事情吗?
    • 谢谢。这就说得通了。我想我现在开始理解这一点 - 我只需要在实际编码之前隐式拦截它,然后转换然后编码?如果有多个参数我不想显示,如果它是空的,我是否会单独选择它们(以获取 option[Json]),然后将它们作为一个数组链接起来?
    • @Josh 可以在不知道更多细节的情况下肯定地说(可能会提出一个新问题),但听起来你走在正确的轨道上。基本思想是,如果您有非标准的东西,即由 argonaut 定义,那么您必须创建 EncodeJson 类型类的自定义实例。从类型 X 到实际 JSON 字符串的任何转换都是这样的:X -> Json -> String。两个箭头都由 argonaut 处理,但它是第一个可以通过 EncodeJson 覆盖的箭头。
    • 我忘了提到 Json 是 Argonaut 的 JSON 字符串的树表示。另外,我错过了上面的几句话。我希望你能推断出来,因为我不能再编辑评论了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多