Skip to content

Instantly share code, notes, and snippets.

@hermanbanken
Last active November 8, 2016 11:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hermanbanken/98057a12f349ddbc6fab9575b8aa5f2e to your computer and use it in GitHub Desktop.
Save hermanbanken/98057a12f349ddbc6fab9575b8aa5f2e to your computer and use it in GitHub Desktop.
JSON readNullable bug
name := """test"""
version := "1.0-SNAPSHOT"
scalaVersion := "2.11.6"
libraryDependencies ++= Seq(
"org.specs2" % "specs2_2.11" % "3.7"
)
lazy val root = (project in file(".")).enablePlugins(PlayScala)
package controllers
import org.specs2.mutable.Specification
import play.api.libs.functional.syntax._
import play.api.libs.json._
object JsonTest {
val json = Json.obj(
"foo" -> Json.obj("a" -> 1, "b" -> 0),
"barA" -> 0,
"barB" -> 0,
"barC" -> 0
)
val json2 = Json.obj(
"foo" -> Json.obj("a" -> 1, "b" -> 0),
"bar" -> Json.obj(
"barA" -> 0,
"barB" -> 0,
"barC" -> 0)
)
case class Root(foo: Foo, bar: Bar)
case class Foo(a: Int, b: Int)
case class Bar(a: Int, b: Int, c: Int)
implicit val fooReads: Reads[Foo] = (
(__ \ "a").read[Int] and
(__ \ "b").read[Int]
)(Foo.apply _)
implicit val barReads: Reads[Bar] = (
(__ \ "barA").read[Int] and
(__ \ "barB").read[Int] and
(__ \ "barC").read[Int]
)(Bar.apply _)
val nonComposableRootReads: Reads[Root] = (
(__ \ "foo").read[Foo] and
(__ \ "barA").read[Int] and
(__ \ "barB").read[Int] and
(__ \ "barC").read[Int]
)((f, a, b, c) => Root(f, Bar(a, b, c)))
val composableRootReads: Reads[Root] = (
(__ \ "foo").read[Foo] and
__.read[Bar]
)(Root.apply _)
val composableRootReadsNullable: Reads[Root] = (
(__ \ "foo").read[Foo] and
__.readNullable[Bar]
)((foo, barOpt) => Root(foo, barOpt.getOrElse(Bar(-1, -1, -1))))
val composableRootReadsNullableScoped: Reads[Root] = (
(__ \ "foo").read[Foo] and
(__ \ "bar").readNullable[Bar]
)((foo, barOpt) => Root(foo, barOpt.getOrElse(Bar(-1, -1, -1))))
}
class JsonTest extends Specification {
import JsonTest._
"JSON parser" should {
"parse using the non-composable fashion" in {
val root = Json.fromJson[Root](json)(nonComposableRootReads)
root should beEqualTo(JsSuccess(Root(Foo(1, 0), Bar(0, 0, 0))))
}
"parse a delegate using partial readers" in {
val root = Json.fromJson[Root](json)(composableRootReads)
root should beEqualTo(JsSuccess(Root(Foo(1, 0), Bar(0, 0, 0))))
}
// Fails because of https://github.com/playframework/playframework/blob/2.5.x/framework/src/play-json/src/main/scala/play/api/libs/json/JsPath.scala#L184
"parse a nullable delegate using partial readers" in {
val root = Json.fromJson[Root](json)(composableRootReadsNullable)
root should beEqualTo(JsSuccess(Root(Foo(1, 0), Bar(0, 0, 0))))
}
"parse a nullable delegate using partial readers with nested path" in {
val root = Json.fromJson[Root](json2)(composableRootReadsNullableScoped)
root should beEqualTo(JsSuccess(Root(Foo(1, 0), Bar(0, 0, 0))))
}
}
}
// Comment to get more information during initialization
logLevel := Level.Warn
// The Typesafe repository
resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/"
// Use the Play sbt plugin for Play projects
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.0")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment