[英]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.