播放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实例
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没问题:
{"id":1, "value": "foo", "status":"pending"}
但是从中读取会由于缺少"/status"路径而产生JsError.
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)
推荐答案
播放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-extra
there is more to the library you may want to check: play-json-extra
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.
我认为这有2个主要缺陷:
This has 2 major flaws in my opinion:
- 默认密钥名称在字符串中,不会因重构而被占用
- 默认值是重复的,如果在一个位置更改默认值,则需要在另一位置手动更改
这篇关于播放2 JSON格式中缺少属性的默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!