Scala Generic Function... using T in Function

263 Views Asked by At

I'm a bit confused why the code below doesn't work:

  implicit val connectReads: Reads[ConnectCommand] = (
    (JsPath \ "uuid").read[String]
    )(ConnectCommand.apply _)

  private def generateMessage[T](json: JsValue) = json.validate[T] match {
    case s: JsSuccess[T] => s.asOpt
    case e: JsError => None
  }

The function would be called as follows:

generateMessage[ConnectCommand](json)

I'm getting the following errors:

Error:(59, 64) No Json deserializer found for type T. Try to implement an implicit Reads or Format for this type.
  private def generateMessage[T](json: JsValue) = json.validate[T] match {
                                                               ^
Error:(59, 64) not enough arguments for method validate: (implicit rds: play.api.libs.json.Reads[T])play.api.libs.json.JsResult[T].
Unspecified value parameter rds.
  private def generateMessage[T](json: JsValue) = json.validate[T] match {
                                                           ^

I'm fairly new to Scala generics... is there any way to do what I'm trying to do here?

2

There are 2 best solutions below

2
On BEST ANSWER

According to the documentation JsValue.validate requires an implicit Reads for your type to be available:

def validate[T](implicit rds: Reads[T]): JsResult[T] 

Assuming you have it available at the place you are calling generateMessage from, you have to pass it into generateMessage, so that validate would see it as well:

private def generateMessage[T](json: JsValue)(implicit rds: Reads[T])

or the shorter form:

private def generateMessage[T : Reads](json: JsValue)
1
On

This is not really related to generics, but rather implicits and how libraries require you to define implicits types and import them.

This is required because the validate function does not know the format of your JsValue, therefore requires the implicit scope to provide one. It then uses the format to validate it. It is confusing at first but eventually is nicer because you don't have to explicitly provide the format for every method call when a JSON format is required.

Also these are the two lines that give it away in the error message:

Try to implement an implicit Reads or Format for this type.

not enough arguments for method validate: (implicit rds: play.api.libs.json.Reads[T])

We see that you either need to import the implicit Format/Reads or define one yourself. You can read up on how to do this in the relevant section of the Play! documentation.

EDIT:

Your method is missing the implicit parameter (implicit reads: Reads[T]) to pass it on to the validate function:

private def generateMessage[T](json: JsValue)(implicit reads: Reads[T]) = json.validate[T] match {
 case s: JsSuccess[T] => s.asOpt
 case e: JsError => None
}