Created
September 18, 2020 12:54
-
-
Save domdorn/46299b2013b8837566cdf8aa23541462 to your computer and use it in GitHub Desktop.
Play Json Inheritance
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import play.api.libs.json._ | |
sealed trait Animal { | |
val `type`: String | |
} | |
case class Cat(name: String) extends Animal { | |
override val `type`: String = "cat" | |
} | |
case class Dog(name: String) extends Animal { | |
override val `type`: String = "dog" | |
} | |
trait AnimalJsonSupport | |
extends de.heikoseeberger.akkahttpplayjson.PlayJsonSupport { | |
implicit val catReads: Reads[Cat] = | |
(JsPath \ "name").read[String].map(Cat(_)) | |
implicit val dogReads: Reads[Dog] = | |
(JsPath \ "name").read[String].map(Dog(_)) | |
implicit val catWrites: Writes[Cat] = e => | |
JsObject(Seq("type" -> JsString("cat"), "name" -> JsString(e.name))) | |
implicit val dogWrites: Writes[Dog] = e => | |
JsObject(Seq("type" -> JsString("dog"), "name" -> JsString(e.name))) | |
implicit val animalReads: Reads[Animal] = Reads[Animal](jsValue => { | |
(jsValue \ "type").toEither | |
.map( | |
v => | |
v.as[String] match { | |
case "cat" => catReads.map(_.asInstanceOf[Animal]).reads(jsValue) | |
case "dog" => dogReads.map(_.asInstanceOf[Animal]).reads(jsValue) | |
case t => | |
JsError((JsPath \ "type"), "unkown animal type $t") | |
.asInstanceOf[JsResult[Animal]] | |
} | |
) | |
.fold(v => JsError(JsPath, v).asInstanceOf[JsResult[Animal]], v => v) | |
}) | |
implicit val animalWrites: Writes[Animal] = Json.writes[Animal] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.scalatest.matchers.should.Matchers | |
import org.scalatest.wordspec.AnyWordSpec | |
import play.api.libs.json.Json | |
class AnimalJsonSupportSpec | |
extends AnyWordSpec | |
with Matchers | |
with AnimalJsonSupport | |
{ | |
val catJsonString = | |
""" | |
|{ | |
|"type":"cat", | |
|"name":"test" | |
|} | |
|""".stripMargin.replace("\n", "") | |
val dummyRequestResponse = Cat("test") | |
"The AnimalJsonSupport" when { | |
"handling the Cat-Type" should { | |
"correctly serialize the response" in { | |
Json.toJson(dummyRequestResponse).toString() should ===(catJsonString) | |
} | |
"correctly deserialize the cat response" in { | |
val parseResult = Json.fromJson[Animal](Json.parse(catJsonString)) | |
parseResult.get should ===(dummyRequestResponse) | |
} | |
} | |
"handling the Dog-Type" should { | |
"correctly deserialize the dog response" in { | |
val json = | |
""" | |
|{ | |
|"type":"dog", | |
|"name":"test2" | |
|} | |
|""".stripMargin.replace("\n", "") | |
val parseResult = Json.fromJson[Animal](Json.parse(json)) | |
parseResult.get should ===(Dog("test2")) | |
} | |
} | |
"handling other types" should { | |
"fail trying to deserialize a unknown type" in { | |
val json = """ | |
|{ | |
|"type":"unknown", | |
|"name":"test" | |
|} | |
|""".stripMargin.replace("\n", "") | |
val result = Json.fromJson[Animal](Json.parse(json)) | |
result.isError shouldBe(true) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment