在我们的应用程序中,我们有非常复杂的对象结构,它们被转换为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
可以保留为空,理想情况下甚至不应该存在)。
我明白我们必须创建单独的Reads&amp; amp;写给那个。
但是,我不确定,如何实现对不同类型的data
做出不同反应的逻辑。
当然,始终可以选择创建完全自定义的writes
:
override def writes(column: ChecklistColumn): JsValue = {...}
但是,这将在代码中产生巨大的复杂性,难以维护。
实现类似内容的最简洁方法是什么?
答案 0 :(得分:2)
看看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!!!"
// }