Skip to content

Instantly share code, notes, and snippets.

@VlachJosef
Last active December 22, 2016 15:57
Show Gist options
  • Save VlachJosef/c09ac88998589ad79244 to your computer and use it in GitHub Desktop.
Save VlachJosef/c09ac88998589ad79244 to your computer and use it in GitHub Desktop.
Using tagged type with play-json
package taggettest
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import play.api.libs.json._
import scalaz.{Tag, @@}
sealed trait UserTag
case class User(id: Long @@ UserTag, name: String)
class TaggedSuite extends FlatSpec with Matchers {
implicit def taggedLongFormat[T]: Format[Long @@ T] = new Format[Long @@ T] {
def reads(json: JsValue): JsResult[Long @@ T] = json match {
case JsNumber(v) => JsSuccess(Tag.of[T](v.toLong))
case unknown => JsError(s"Number value expected, got: $unknown")
}
def writes(v: Long @@ T): JsValue = JsNumber(Tag.unwrap(v))
}
implicit def taggedStringFormat[T]: Format[String @@ T] = new Format[String @@ T] {
def reads(json: JsValue): JsResult[String @@ T] = json match {
case JsString(v) => JsSuccess(Tag.of[T](v))
case unknown => JsError(s"String value expected, got: $unknown")
}
def writes(v: String @@ T): JsValue = JsString(Tag.unwrap(v))
}
implicit val userFormat = Json.format[User]
"User containing tagged type" should "be convertible to String from case class" in {
val user = User(Tag.of[UserTag](1), "Josef")
val userJson = Json.toJson(user)
val userString = Json.prettyPrint(userJson)
userString should be(
"""|{
| "id" : 1,
| "name" : "Josef"
|}""".stripMargin)
}
it should "be convertible to case class from String" in {
val userString = """|{
| "id" : 1,
| "name" : "Josef"
|}""".stripMargin
val user = Json.fromJson[User](Json.parse(userString))
user.get should be (User(Tag.of[UserTag](1), "Josef"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment