Creating Writes[T] for Custom Object

2019-08-04 08:38发布

Play for Scala shows how to convert JSON to a Scala object.

case class Product(ean: Long, name: String, description: String)

    import play.api.libs.json._
    import play.api.libs.functional.syntax._

    implicit val productWrites: Writes[Product] = (
      (JsPath \ "ean").write[Long] and
      (JsPath \ "name").write[String] and
      (JsPath \ "description").write[String]
    )(unlift(Product.unapply))

And then using in REPL:

scala> val p = Product(100, "tilley hat", "Nice hat")
p: Product = Product(100,tilley hat,Nice hat)

scala> Json.toJson(p)
res1: play.api.libs.json.JsValue = {"ean":100,"name":"tilley hat",
                                             "description":"Nice hat"}

What's going on with the last line: (unlift(Product.unapply)) of the Writes[Product]?

1条回答
\"骚年 ilove
2楼-- · 2019-08-04 09:22

Product.unapply _ is a function Product => Option[(Long, String, String)].

Result type of this expression:

(
  (JsPath \ "ean").write[Long] and
  (JsPath \ "name").write[String] and
  (JsPath \ "description").write[String]
)

is FunctionalBuilder[OWrites]#CanBuild3[Long,String,String]. It accepts T => (Long, String, String) as parameter of method apply.

So you have to convert Product => Option[(Long, String, String)] to Product => (Long, String, String).

Method unlift accepts T => Option[R] and returns T => R. Unlifted function throws MatchError instead of None. It produces something like this:

val unlifted = (Product.unapply _) andThen { case Some(r) => r }

Default unapply method for case class should never return None, so for case class unlift is safe.

查看更多
登录 后发表回答