8

我在这里有一个“风格”或“有效 scala”类型的问题:我有一个“FeatureCheck”类,我需要将其序列化为 Json in Play 框架。

case class FeatureCheck(val result: Option[Boolean], val missing: Option[Array[String]], val error: Option[String])

我正在使用自己的“写入”对其进行序列化,但我的代码看起来很像 Java 代码。我只想序列化检查对象中的每个选项,如果它被定义(最终对象不应该有任何空值)。

def writes(check: FeatureCheck): JsValue = {
  val builder = Seq.newBuilder[(String, JsValue)]
  if (check.error.isDefined) {
    builder += "error" -> JsString(check.error.get)
  }
  if (check.missing.isDefined) {
    builder += "missing" -> Json.toJson(check.missing.get)
  }
  if (check.result.isDefined) {
    builder += "result" -> JsBoolean(check.result.get)
  }
  JsObject(builder.result)
}

所以我想知道是否有办法做到这一点,而无需那些丑陋的 if-then,甚至删除序列的构建器。

感谢您提供的任何帮助或评论。

说明:

假设我只想发送 result = true 我希望生成的 Json 为:

{"result":true} 

并不是

{
    "result": true,
    "error": null,
    "missing": []
}
4

3 回答 3

6

鉴于您可以简单地将选项附加到 seq (请参阅Add to list if value is not null),您可以相当优雅地做您想做的事情:

type JsField = (String, JsValue)
def writes(check: FeatureCheck): JsValue = {
  JsObject(
    Seq[JsField]() ++
    check.error.map("error" -> JsString(_)) ++
    check.missing.map("missing" -> Json.toJson(_)) ++
    check.result.map("result" -> JsBoolean(_))    
  )
}
于 2013-04-29T13:27:15.053 回答
4

您可以跳过额外isDefined检查,它只会检查选项值是否为Some. 将在 scala 中getOrElse执行相同的操作。Option

这是一个稍微简单的版本。

def writes(check: FeatureCheck): JsValue = {
  val builder = Seq.newBuilder[(String, JsValue)]
  builder += "error" -> JsString(check.error.getOrElse(""))
  builder += "missing" -> Json.toJson(check.missing.getOrElse({ Array[String]() }))
  builder += "result" -> JsBoolean(check.result.getOrElse(false))
  JsObject(builder.result)
}

这可能被认为更简单。

def writes(check: FeatureCheck): JsValue = JsObject(
  List(
    "error" -> JsString(check.error.getOrElse("")),
    "missing" -> Json.toJson(check.missing.getOrElse({ Array[String]() })),
    "result" -> JsBoolean(check.result.getOrElse(false))
  )
)

编辑

如果您不希望添加不存在的属性,那么我猜这会更优雅:

def writes(check: FeatureCheck): JsValue = JsObject(
  List(
    check.error.map("error" -> JsString(_)),
    check.missing.map("missing" -> Json.toJson(_)),
    check.result.map("result" -> JsBoolean(_))
  ).flatten
)
于 2013-04-29T12:37:01.767 回答
0

另一个选择是在创建 Json 对象后过滤掉空字段,我使用以下 util 方法:

  def filterOutNullFields(jsonObject:JsObject) : JsObject =  {
    jsonObject.fields.foldLeft(jsonObject)((jsonObjectAcc , tupleKeyValue) => {
      if (tupleKeyValue._2.isInstanceOf[JsObject]) {
        val innerJsonObject = filterOutNullFields(tupleKeyValue._2.as[JsObject])
        jsonObjectAcc - tupleKeyValue._1 + (tupleKeyValue._1, innerJsonObject)
      }
      else {
        if (tupleKeyValue._2.equals(JsNull)) {
          jsonObjectAcc - tupleKeyValue._1
        } else {
          jsonObjectAcc
        }
      }
    })
  }

你可以像这样使用它:

val featureCheckJson = Json.toJson(featureCheck)
val featureCheckJsonWithoutNullFields = filterOutNullFields(featureCheckJson.as[JsObject])
于 2017-10-03T06:55:03.120 回答