play 2 JSON 格式中缺失属性的默认值 [英] Defaults for missing properties in play 2 JSON formats
问题描述
我在 play scala 中有一个与以下模型等效的模型:
I have an equivalent of the following model in play scala :
case class Foo(id:Int,value:String)
object Foo{
import play.api.libs.json.Json
implicit val fooFormats = Json.format[Foo]
}
对于下面的 Foo 实例
For the following Foo instance
Foo(1, "foo")
我会得到以下 JSON 文档:
I would get the following JSON document:
{"id":1, "value": "foo"}
这个 JSON 被持久化并从数据存储中读取.现在我的要求发生了变化,我需要向 Foo 添加一个属性.该属性有一个默认值:
This JSON is persisted and read from a datastore. Now my requirements have changed and I need to add a property to Foo. The property has a default value :
case class Foo(id:String,value:String, status:String="pending")
写入 JSON 不是问题:
Writing to JSON is not a problem :
{"id":1, "value": "foo", "status":"pending"}
然而,读取它会产生一个 JsError,因为它缺少/status"路径.
Reading from it however yields a JsError for missing the "/status" path.
我怎样才能提供一个噪音最小的默认值?
How can I provide a default with the least possible noise ?
(ps:我有一个答案,我将在下面发布,但我对此并不满意,并且会投票并接受任何更好的选择)
(ps: I have an answer which I will post below but I am not really satisfied with it and would upvote and accept any better option)
推荐答案
Play 2.6+
根据 @CanardMoussant 的回答,从 Play 2.6 开始,play-json 宏得到了改进并提出了多项新功能包括在反序列化时使用默认值作为占位符:
As per @CanardMoussant's answer, starting with Play 2.6 the play-json macro has been improved and proposes multiple new features including using the default values as placeholders when deserializing :
implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[Foo]
对于低于 2.6 的游戏,最佳选择仍然是使用以下选项之一:
For play below 2.6 the best option remains using one of the options below :
play-json-extra
我发现了一个更好的解决方案来解决我在 play-json 中的大多数缺点,包括问题中的缺点:
I found out about a much better solution to most of the shortcomings I had with play-json including the one in the question:
play-json-extra 使用 [play-json-extensions] 在内部解决此问题中的特定问题.
play-json-extra which uses [play-json-extensions] internally to solve the particular issue in this question.
它包含一个宏,该宏将自动包含序列化器/反序列化器中缺少的默认值,从而使重构更不容易出错!
It includes a macro which will automatically include the missing defaults in the serializer/deserializer, making refactors much less error prone !
import play.json.extra.Jsonx
implicit def jsonFormat = Jsonx.formatCaseClass[Foo]
您可能想查看更多库:play-json-额外
Json 转换器
我目前的解决方案是创建一个 JSON Transformer 并将其与宏生成的 Reads 结合起来.变压器通过以下方法生成:
My current solution is to create a JSON Transformer and combine it with the Reads generated by the macro. The transformer is generated by the following method:
object JsonExtensions{
def withDefault[A](key:String, default:A)(implicit writes:Writes[A]) = __.json.update((__ key).json.copyFrom((__ key).json.pick orElse Reads.pure(Json.toJson(default))))
}
格式定义变为:
implicit val fooformats: Format[Foo] = new Format[Foo]{
import JsonExtensions._
val base = Json.format[Foo]
def reads(json: JsValue): JsResult[Foo] = base.compose(withDefault("status","bidon")).reads(json)
def writes(o: Foo): JsValue = base.writes(o)
}
和
Json.parse("""{"id":"1", "value":"foo"}""").validate[Foo]
确实会生成一个应用了默认值的 Foo 实例.
will indeed generate an instance of Foo with the default value applied.
我认为这有两个主要缺陷:
This has 2 major flaws in my opinion:
- 默认键名称在一个字符串中,不会被重构获取
- 默认值是重复的,如果在一处更改,则需要在另一处手动更改
这篇关于play 2 JSON 格式中缺失属性的默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!