Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala type deferring

I am using Play framework 2.1 and Scala 2.10.1 and would like to build a general function to construct a JsArray out of a List of custom case class.

private def buildJsArray[T](l: List[T])(result: JsArray): JsArray = {
    l match {
      case List() => result
      case x::xs => buildJsArray(xs)(result :+ Json.toJson(x)) // compiling error here!
    }
  }

usage:

val applyJsonArray = buildJsArray(List[Apple])(new JsArray())

However, a compiling error is thrown:

No Json deserializer found for type T. Try to implement an implicit Writes or Format for this 
 type.

I do have a Json deserializer written for the particular case class(i.e., Apple case class).

How do I defer the compiler to check the type of x in runtime rather than in compile time?

Many Thanks!

like image 632
Joyfulvillage Avatar asked Jun 25 '13 05:06

Joyfulvillage


1 Answers

How to fix a error

You have to add an implicit parameter to your method like this:

def buildJsArray[T](l: List[T])(result: JsArray)(implicit tjs: Writes[T]): JsArray

There is such parameter in the Json.toJson method.

The reason why you have to add this parameter is that you know how to convert T to json only when you know what T is. It means you have the method to serialize T only when you call buildJsArray and this parameter allows you to pass this serialization method to the method buildJsArray.

How to build a JSArray

You could just use a constructor of JsArray. It takes a Seq[JsValue]:

new JsArray(l.map{Json.toJson(_)})

There is already an implicit Writes for Traversable so you don't need your own method buildJsArray, you could just use method Json.toJson with parameter of type List[T].

Addition

You should take a look at the collections api. It allows you to write more readable and shorter code:

def buildJsArray[T](l: List[T])(implicit tjs: Writes[T]): JsArray =
  l.foldLeft(new JsArray){ (r, x) => r :+ Json.toJson(x) }
like image 77
senia Avatar answered Oct 16 '22 02:10

senia