play anorm, create a model from json without passing anorm PK value in the json play anorm, create a model from json without passing anorm PK value in the json json json

play anorm, create a model from json without passing anorm PK value in the json


I did not compile this, but it should work:

case class User(  id: Pk[Long] = NotAssigned,  name: String = "",  email: Option[String])implicit object UserReads extends Reads[User] {    def reads(json: JsValue) = JsSuccess(User(      (json \ "id").asOpt[Long].map(id => Id[Long](id)).getOrElse(NotAssigned)      (json \ "name").as[String],      (json \ "email").asOpt[String])  }  implicit object UserWrites extends Writes[User] {    def writes(user: User) = JsObject(Seq(      "id" -> JsNumber(user.id.get),      "name" -> JsString(user.name),      "email" -> Json.toJson(user.email))  }

Basically you take the id as Option[Long] like you did with the email. Then you check if it is set and if yes you create the Pk instance with Id[Long](id) and if not you provide the NotAssigned Pk singleton instance.

Additional Tip

Alternatively you can try to use

implicit val jsonFormatter = Json.format[User]

It will create the Reads and the Writes for you directly at compile time.There are two problem with this if you are using an anorm object directly:

First you need a Format for the Pk[Long]

implicit object PkLongFormat extends Format[Pk[Long]] {  def reads(json: JsValue): JsResult[Pk[Long]] = {    json.asOpt[Long].map {      id => JsSuccess(Id[Long](id))    }.getOrElse(JsSuccess(NotAssigned))  }  def writes(id: Pk[Long]): JsNumber = JsNumber(id.get)}

Second it does not work, if you do not send an id at all, not even with value null, so your client needs to send {"id": null, "name": "Tim"} because it does not even try to call the PkFormatter which could handle the JsUndefined, but simply gives you an "validate.error.missing-path" error

If you don't want to send null ids you cannot use the macro Json.format[User]


Type anorm.Pk is almost exactly like scala.Option in form and function. Avoid writing concrete Reads and Writes for all types it might possibly contain. An example that follows the OptionReads and OptionWrites implementations is as follows:

implicit def PkWrites[T](implicit w: Writes[T]): Writes[Pk[T]] = new Writes[Pk[T]] {  def writes(o: Pk[T]) = o match {    case Id(value) => w.writes(value)    case NotAssigned => JsNull  }}implicit def PkReads[T](implicit r: Reads[T]): Reads[Pk[T]] = new Reads[Pk[T]] {  def reads(js: JsValue): JsResult[Pk[T]] =    r.reads(js).fold(e => JsSuccess(NotAssigned), v => JsSuccess(Id(v)))}

This way, you support every T for which there's a respective Reads[T] or Writes[T], and it's more reliable in handling Id and NotAssigned.