Play\'s JSON serialization is by default permissive when serializing from JSON into a case class. For example.
case class Stuff(name: String, value: Option[
Inspired from Travis' comment to use LabelledGeneric
I was able achieve compile time safe solution.
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
now keys.map (toStringName).toList
will give you
res0: List[String] = List(bar, boo)
You can verify that the object doesn't contain extra keys before performing your own decoding:
import play.api.data.validation.ValidationError
def onlyFields(allowed: String*): Reads[JsObject] = Reads.filter(
ValidationError("One or more extra fields!")
)(_.keys.forall(allowed.contains))
Or if you don't care about error messages (and that one's not very helpful, anyway):
def onlyFields(allowed: String*): Reads[JsObject] =
Reads.verifying(_.keys.forall(allowed.contains))
And then:
implicit val stuffReads: Reads[Stuff] = onlyFields("name", "value") andThen (
(__ \ 'name).read[String] and
(__ \ 'value).readNullable[Boolean]
)(Stuff)
The repetition isn't very nice, but it works.