我在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文档:
{"id":1, "value": "foo"}
该JSON将持久保存并从数据存储中读取。现在,我的要求已更改,我需要向Foo添加一个属性。该属性具有默认值:
case class Foo(id:String,value:String, status:String="pending")
写入JSON没问题:
{"id":1, "value": "foo", "status":"pending"}
但是,从中读取会由于缺少“ / status”路径而产生JsError。
如何提供具有最小噪声的默认设置?
(ps:我有一个答案,我将在下面发布,但我对此并不满意,会投票并接受任何更好的选择)
播放2.6
按照@CanardMoussant的回答,从Play 2.6开始,对play- json宏进行了改进,并提出了多个新功能,包括在反序列化时使用默认值作为占位符:
implicit def jsonFormat = Json.using[Json.WithDefaultValues].format[Foo]
对于低于2.6的比赛,最好的选择仍然是使用以下选项之一:
播放json-extra
我发现了一个更好的解决方案,可以解决我在play-json中遇到的大多数缺点,包括问题中的一个:
play-json-extra内部使用[play-json-extensions]解决此问题中的特定问题。
它包含一个宏,该宏将自动在序列化器/反序列化器中包含缺少的默认值,从而使重构的错误率大大降低!
import play.json.extra.Jsonx implicit def jsonFormat = Jsonx.formatCaseClass[Foo]
库中还有更多您可能要检查的内容:play-json-extra
杰森变压器
我当前的解决方案是创建一个JSON Transformer,并将其与宏生成的Reads结合起来。变压器通过以下方法生成:
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实例,并应用默认值。
我认为这有2个主要缺陷: