如何在Play 2.x中强制执行JSON的严格序列化

如何在Play 2.x中强制执行JSON的严格序列化,json,scala,playframework-2.0,Json,Scala,Playframework 2.0,当从JSON序列化到case类时,Play的JSON序列化在默认情况下是允许的。比如说 case class Stuff(name: String, value: Option[Boolean]) implicit val stuffReads: Reads[Stuff] = ( ( __ \ 'name).read[String] and ( __ \ 'value).readNullable[Boolean] )(Stuff.apply _) 如果收到以下JSON: {name:

当从JSON序列化到case类时,Play的JSON序列化在默认情况下是允许的。比如说

case class Stuff(name: String, value: Option[Boolean])

implicit val stuffReads: Reads[Stuff] = (
  ( __ \ 'name).read[String] and
  ( __ \ 'value).readNullable[Boolean]
)(Stuff.apply _)
如果收到以下JSON:

{name: "My Stuff", value: true, extraField: "this shouldn't be here"}
它将以“JsSuccess”成功,并放弃“extraField”


如果存在“未处理”字段,是否有方法构造Json Reads函数以使其返回JsError?

在执行自己的解码之前,您可以验证该对象不包含额外的键:

import play.api.data.validation.ValidationError

def onlyFields(allowed: String*): Reads[JsObject] = Reads.filter(
  ValidationError("One or more extra fields!")
)(_.keys.forall(allowed.contains))
或者,如果您不关心错误消息(不管怎样,这条消息也没有多大帮助):

然后:

implicit val stuffReads: Reads[Stuff] = onlyFields("name", "value") andThen (
  (__ \ 'name).read[String] and
  (__ \ 'value).readNullable[Boolean]
)(Stuff)
重复性不是很好,但它很有效。

受“使用
LabelledGeneric的注释”的启发,我能够实现编译时安全的解决方案

object toStringName extends Poly1 {
    implicit def keyToStrName[A] = at[Symbol with A](_.name)
}
case class Foo(bar: String, boo: Boolean)

val labl = LabelledGeneric[Foo]
val keys = Keys[labl.Repr].apply
现在
keys.map(ToString名称)。toList
将为您提供


res0:List[String]=List(bar,boo)

想知道您今天是否会以不同的方式来添加更多编译时魔法,以获得
case类
属性名,而不是
onlyFields(“name”,“value”)
变量函数?在
onlyFields
方法中硬编码属性名称是可行的,但在
onlyFields
修改
case class
时,要记住更新/添加/删除
onlyFields
中的字段名称会遇到维护挑战,因为
onlyFields
没有编译时安全性,只有在单元测试/运行时才会显示缺少的属性。有什么方法可以在编译时实现这一点吗?你完全可以用宏来实现,或者用Shapeless的
LabelledGeneric
来实现。我会尽量找时间写一篇博文来做这件事,但我不能保证我会在本周完成。
object toStringName extends Poly1 {
    implicit def keyToStrName[A] = at[Symbol with A](_.name)
}
case class Foo(bar: String, boo: Boolean)

val labl = LabelledGeneric[Foo]
val keys = Keys[labl.Repr].apply