2

So, I've just recently started learning Scala. Sorry for my incompetence in advance.

I tried to look up my answer on stackoverflow. I was able to find several related topics, but I didn't spot my problem.

I'm trying to send a json response based on a Scala object. I have an Action and I'm doing the following:

def oneCredential = Action {
   val cred = Credential("John", "Temp", "5437437")
   Ok(Json.toJson(cred))
}

I've created a case class and appropriate implicit Writes[T] for it

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

case class Credential(name: String, account: String, password: String)

object  Credential{
  implicit val credentialWrites = (
    (__ \ "name").write[String] and
    (__ \ "account").write[String] and
    (__ \ "password").write[String]
  )(Credential)
}

When I'm trying to run this, I've the following error: "Overloaded method value [apply] cannot be applied to (models.Credential.type)". Also, I tried this

implicit val credentialWrites = (
        (__ \ "name").write[String] and
        (__ \ "account").write[String] and
        (__ \ "password").write[String]
)(Credential.apply _)

Fail. The error: could not find implicit value for parameter fu: play.api.libs.functional.Functor[play.api.libs.json.OWrites]

Then this:

implicit val credentialWrites = (
    (__ \ "name").writes[String] and
    (__ \ "account").writes[String] and
    (__ \ "password").writes[String]
)(Credential)

Another fail: "value writes is not a member of play.api.libs.json.JsPath Note: implicit value credentialWrites is not applicable here because it comes after the application point and it lacks an explicit result type". Right, I understood the first part of an error, but not the second.

Finally I found a shorthand solution:

implicit val credentialWrites = Json.writes[Credential]

With this I've got no errors and the code finally worked. I've found the solution on this blog. It's said that the shorthand form is exactly the same as the one with "writes" above. But this "long" form didn't work for me.

Why is shorthand version working, while the long one isn't? Can somebody explain this?

Thank you!

PS Scala version: 2.10.2

1 Answer 1

3

The definitions you've given would work for Reads, but Writes needs a different kind of argument at the end. Take the following example:

case class Baz(foo: Int, bar: String)

val r = (__ \ 'foo).read[Int] and (__ \ 'bar).read[String]
val w = (__ \ 'foo).write[Int] and (__ \ 'bar).write[String]

r can be applied to a function (Int, String) => A to get a Reads[A], which means we can use it as follows (these are all equivalent):

val bazReader1 = r((foo: Int, bar: String) => Baz(foo, bar))
val bazReader2 = r(Baz.apply _)
val bazReader3 = r(Baz)

What we're doing is lifting the function into the applicative functor for Reads so that we can apply it to our Reads[Int] and Reads[String] (but you don't need to care about that if you don't want to).

w takes a different kind of argument (again, you don't need to care, but this is because Writes has a contravariant functor—it doesn't have an applicative functor):

val bazWriter1 = w((b: Baz) => (b.foo, b.bar))

We could write this equivalently as the following:

val bazWriter2 = w(unlift(Baz.unapply))

Here we're using the case class's automatically generated extractor, unapply, which returns an Option[(Int, String)]. We know in this case that it'll always return a Some, so we can use unlift (which comes from the functional syntax package, and just calls the standard library's Function.unlift) to turn the Baz => Option[(Int, String)] into the required Baz => (Int, String).

So just change your final line to )(unlift(Credential.unapply)) and you're good to go.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.