|
Play Framework/Scala example source code file (JsonSpec.scala)
The JsonSpec.scala Play Framework example source code/* * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> */ package play.api.libs.json import org.specs2.mutable._ import com.fasterxml.jackson.databind.JsonNode import play.api.libs.functional.syntax._ import play.api.libs.json.Json._ object JsonSpec extends Specification { case class User(id: Long, name: String, friends: List[User]) implicit val UserFormat: Format[User] = ( (__ \ 'id).format[Long] and (__ \ 'name).format[String] and (__ \ 'friends).lazyFormat(Reads.list(UserFormat), Writes.list(UserFormat)) )(User, unlift(User.unapply)) case class Car(id: Long, models: Map[String, String]) implicit val CarFormat = ( (__ \ 'id).format[Long] and (__ \ 'models).format[Map[String, String]] )(Car, unlift(Car.unapply)) import java.util.Date import java.text.SimpleDateFormat val dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'" // Iso8601 format (forgot timezone stuff) val dateParser = new SimpleDateFormat(dateFormat) case class Post(body: String, created_at: Option[Date]) implicit val PostFormat = ( (__ \ 'body).format[String] and (__ \ 'created_at).formatNullable[Option[Date]]( Format( Reads.optionWithNull(Reads.dateReads(dateFormat)), Writes.optionWithNull(Writes.dateWrites(dateFormat)) ) ).inmap( optopt => optopt.flatten, (opt: Option[Date]) => Some(opt) ) )(Post, unlift(Post.unapply)) "JSON" should { "equals JsObject independently of field order" in { Json.obj( "field1" -> 123, "field2" -> "beta", "field3" -> Json.obj( "field31" -> true, "field32" -> 123.45, "field33" -> Json.arr("blabla", 456L, JsNull) ) ) must beEqualTo( Json.obj( "field2" -> "beta", "field3" -> Json.obj( "field31" -> true, "field33" -> Json.arr("blabla", 456L, JsNull), "field32" -> 123.45 ), "field1" -> 123 ) ) Json.obj( "field1" -> 123, "field2" -> "beta", "field3" -> Json.obj( "field31" -> true, "field32" -> 123.45, "field33" -> Json.arr("blabla", JsNull) ) ) must not equalTo( Json.obj( "field2" -> "beta", "field3" -> Json.obj( "field31" -> true, "field33" -> Json.arr("blabla", 456L), "field32" -> 123.45 ), "field1" -> 123 ) ) Json.obj( "field1" -> 123, "field2" -> "beta", "field3" -> Json.obj( "field31" -> true, "field32" -> 123.45, "field33" -> Json.arr("blabla", 456L, JsNull) ) ) must not equalTo( Json.obj( "field3" -> Json.obj( "field31" -> true, "field33" -> Json.arr("blabla", 456L, JsNull), "field32" -> 123.45 ), "field1" -> 123 ) ) } "serialize and deserialize maps properly" in { val c = Car(1, Map("ford" -> "1954 model")) val jsonCar = toJson(c) jsonCar.as[Car] must equalTo(c) } "serialize and deserialize" in { val luigi = User(1, "Luigi", List()) val kinopio = User(2, "Kinopio", List()) val yoshi = User(3, "Yoshi", List()) val mario = User(0, "Mario", List(luigi, kinopio, yoshi)) val jsonMario = toJson(mario) jsonMario.as[User] must equalTo(mario) } "Complete JSON should create full Post object" in { val postJson = """{"body": "foobar", "created_at": "2011-04-22T13:33:48Z"}""" val expectedPost = Post("foobar", Some(dateParser.parse("2011-04-22T13:33:48Z"))) val resultPost = Json.parse(postJson).as[Post] resultPost must equalTo(expectedPost) } "Optional parameters in JSON should generate post w/o date" in { val postJson = """{"body": "foobar"}""" val expectedPost = Post("foobar", None) val resultPost = Json.parse(postJson).as[Post] resultPost must equalTo(expectedPost) } "Invalid parameters shoud be ignored" in { val postJson = """{"body": "foobar", "created_at":null}""" val expectedPost = Post("foobar", None) val resultPost = Json.parse(postJson).as[Post] resultPost must equalTo(expectedPost) } "Serialize long integers correctly" in { val t = 1330950829160L val m = Map("timestamp" -> t) val jsonM = toJson(m) (jsonM \ "timestamp").as[Long] must equalTo(t) (jsonM.toString must equalTo("{\"timestamp\":1330950829160}")) } "Serialize and deserialize BigDecimals" in { val n = BigDecimal("12345678901234567890.42") val json = toJson(n) json must equalTo (JsNumber(n)) fromJson[BigDecimal](json) must equalTo(JsSuccess(n)) } "Not lose precision when parsing BigDecimals" in { val n = BigDecimal("12345678901234567890.123456789") val json = toJson(n) parse(stringify(json)) must equalTo(json) } "Not lose precision when parsing big integers" in { // By big integers, we just mean integers that overflow long, since Jackson has different code paths for them // from decimals val i = BigDecimal("123456789012345678901234567890") val json = toJson(i) parse(stringify(json)) must equalTo(json) } "Serialize and deserialize Lists" in { val xs: List[Int] = (1 to 5).toList val json = arr(1, 2, 3, 4, 5) toJson(xs) must equalTo (json) fromJson[List[Int]](json) must equalTo (JsSuccess(xs)) } "Serialize and deserialize Jackson ObjectNodes" in { val on = JacksonJson.mapper.createObjectNode() .put("foo", 1).put("bar", "two") val json = Json.obj("foo" -> 1, "bar" -> "two") toJson(on) must equalTo (json) fromJson[JsonNode](json).map(_.toString) must_== JsSuccess(on.toString) } "Serialize and deserialize Jackson ArrayNodes" in { val an = JacksonJson.mapper.createArrayNode() .add("one").add(2) val json = Json.arr("one", 2) toJson(an) must equalTo (json) fromJson[JsonNode](json).map(_.toString) must_== JsSuccess(an.toString) } "Map[String,String] should be turned into JsValue" in { val f = toJson(Map("k"->"v")) f.toString must equalTo("{\"k\":\"v\"}") } "Can parse recursive object" in { val recursiveJson = """{"foo": {"foo":["bar"]}, "bar": {"foo":["bar"]}}""" val expectedJson = JsObject(List( "foo" -> JsObject(List( "foo" -> JsArray(List[JsValue](JsString("bar"))) )), "bar" -> JsObject(List( "foo" -> JsArray(List[JsValue](JsString("bar"))) )) )) val resultJson = Json.parse(recursiveJson) resultJson must equalTo(expectedJson) } "Can parse null values in Object" in { val postJson = """{"foo": null}""" val parsedJson = Json.parse(postJson) val expectedJson = JsObject(List("foo" -> JsNull)) parsedJson must equalTo(expectedJson) } "Can parse null values in Array" in { val postJson = """[null]""" val parsedJson = Json.parse(postJson) val expectedJson = JsArray(List(JsNull)) parsedJson must equalTo(expectedJson) } "JSON pretty print" in { val js = Json.obj( "key1" -> "toto", "key2" -> Json.obj("key21" -> "tata", "key22" -> 123), "key3" -> Json.arr(1, "tutu") ) Json.prettyPrint(js) must beEqualTo("""{ "key1" : "toto", "key2" : { "key21" : "tata", "key22" : 123 }, "key3" : [ 1, "tutu" ] }""") } "null root object should be parsed as JsNull" in { parse("null") must_== JsNull } "asciiStringify should escape non-ascii characters" in { val js = Json.obj( "key1" -> "\u2028\u2029\u2030", "key2" -> "\u00E1\u00E9\u00ED\u00F3\u00FA", "key3" -> "\u00A9\u00A3", "key4" -> "\u6837\u54C1" ) Json.asciiStringify(js) must beEqualTo( "{\"key1\":\"\\u2028\\u2029\\u2030\","+ "\"key2\":\"\\u00E1\\u00E9\\u00ED\\u00F3\\u00FA\","+ "\"key3\":\"\\u00A9\\u00A3\","+"" + "\"key4\":\"\\u6837\\u54C1\"}") } "asciiStringify should escape ascii characters properly" in { val js = Json.obj( "key1" -> "ab\n\tcd", "key2" -> "\"\r" ) Json.asciiStringify(js) must beEqualTo("""{"key1":"ab\n\tcd","key2":"\"\r"}""") } } "JSON Writes" should { "write list/seq/set/map" in { import Writes._ Json.toJson(List(1, 2, 3)) must beEqualTo(Json.arr(1, 2, 3)) Json.toJson(Set("alpha", "beta", "gamma")) must beEqualTo(Json.arr("alpha", "beta", "gamma")) Json.toJson(Seq("alpha", "beta", "gamma")) must beEqualTo(Json.arr("alpha", "beta", "gamma")) Json.toJson(Map("key1" -> "value1", "key2" -> "value2")) must beEqualTo(Json.obj("key1" -> "value1", "key2" -> "value2")) implicit val myWrites = ( (__ \ 'key1).write(constraints.list[Int]) and (__ \ 'key2).write(constraints.set[String]) and (__ \ 'key3).write(constraints.seq[String]) and (__ \ 'key4).write(constraints.map[String]) ).tupled Json.toJson( List(1, 2, 3), Set("alpha", "beta", "gamma"), Seq("alpha", "beta", "gamma"), Map("key1" -> "value1", "key2" -> "value2") ) must beEqualTo( Json.obj( "key1" -> Json.arr(1, 2, 3), "key2" -> Json.arr("alpha", "beta", "gamma"), "key3" -> Json.arr("alpha", "beta", "gamma"), "key4" -> Json.obj("key1" -> "value1", "key2" -> "value2") ) ) } "write in 2nd level" in { case class TestCase(id: String, attr1: String, attr2: String) val js = Json.obj( "id" -> "my-id", "data" -> Json.obj( "attr1" -> "foo", "attr2" -> "bar" ) ) implicit val testCaseWrites: Writes[TestCase] = ( (__ \ "id").write[String] and (__ \ "data" \ "attr1").write[String] and (__ \ "data" \ "attr2").write[String] )(unlift(TestCase.unapply)) Json.toJson(TestCase("my-id", "foo", "bar")) must beEqualTo(js) } } } Other Play Framework source code examplesHere is a short list of links related to this Play Framework JsonSpec.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.