簡體   English   中英

播放Scala JSON-有條件地在Writes中將字段添加到JSON對象

[英]Play Scala JSON - conditionally add field to JSON object in Writes

在我們的應用程序中,我們具有非常復雜的對象結構,這些對象將被轉換為JSON並返回。 到目前為止,大多數格式化的文件都是對稱的(除了一些非常特殊的情況,甚至出於安全原因,這些情況也是如此)。

現在,我們面臨着一個更復雜的案例,其中將對象轉換為JSON(寫入)需要在轉換時創建一個附加字段,而case類沒有該字段。 例如,這是我們現有的格式化程序之一:

case class ChecklistColumn(kind: ColumnKind.Value, descriptor: Descriptor.Value, data: JsValue) extends Column

implicit val checklistResultChecklistDataFormat: Format[ChecklistColumn] = (
  (__ \ "kind").format[ColumnKind.Value] and
  (__ \ "descriptor").format[Descriptor.Value] and
  (__ \ "data").format[JsValue]
)(ChecklistColumn.apply, unlift(ChecklistColumn.unapply))

這將創建一個類似於以下內容的json:

{
  "kind": <String>,
  "descriptor": <String>,
  "data": <JsValue>
}

我們需要實現的是:

{
  "kind": <String>,
  "descriptor": <String>,
  "data": <JsValue>,
  "normalized_data": <JsString>
}

但是,僅在數據為JsString類型的情況下(在任何其他情況下normalized_data都可以留空,理想情況下, JsString甚至不應該存在)。

我確實知道我們必須為此創建單獨的讀取和寫入。 但是,我不確定如何實現對不同類型的data做出不同反應的邏輯。

當然,總有一個選項可以創建完全自定義的writes

override def writes(column: ChecklistColumn): JsValue = {...}

但是,這將在難以維護的代碼中造成巨大的復雜性。

實現這樣的最干凈的方法是什么?

看看ScalaJsonTransformers 您可以創建一個轉換器,該轉換器從字符串數據值創建標准化字段,並將其用於將原始Format轉換為新的Writes 這是一個稍微簡化的示例,無疑可以改進(您將需要檢查各種邊緣情況):

case class ChecklistColumn(kind: String, descriptor: String, data: JsValue)

// The original format.
val checklistFormat: Format[ChecklistColumn] = (
  (__ \ "kind").format[String] and
  (__ \ "descriptor").format[String] and
  (__ \ "data").format[JsValue]
)(ChecklistColumn.apply, unlift(ChecklistColumn.unapply))

// A transformer that looks for a "data" field with a string
// value and adds the normalized_data field if it finds one.
val checklistTransformer: Reads[JsObject] = JsPath.json.update(
  (__ \ "data").read[String].flatMap (
     str => (__ \ "normalized_data").json.put(JsString(str + "!!!"))))

// A new derived Writes which writes the transformed value if
// the transformer succeeds (a data string), otherwise the
// original value.
implicit val checklistWrites: Writes[ChecklistColumn] = checklistFormat
  .transform (js => js.transform(checklistTransformer).getOrElse(js))

這給了我:

Json.prettyPrint(Json.toJson(ChecklistColumn("a", "b", JsNumber(1))))
// {
//   "kind" : "a",
//   "descriptor" : "b",
//   "data" : 1
// }

Json.prettyPrint(Json.toJson(ChecklistColumn("a", "b", JsString("c"))))
// {
//   "kind" : "a",
//   "descriptor" : "b",
//   "data" : "c",
//   "normalized_data" : "c!!!"
// }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM