Kevin Meredith
Kevin Meredith

Reputation: 41939

Json#arr w/ List[Int] Input

Looking at this helpful answer on encoding a List[A] in the Play JSON library,

I tried to use Json#arr:

import play.api.libs.json._

scala> Json.arr( 1, 2, 3 )
res21: play.api.libs.json.JsArray = [1,2,3]

All works well so far, but what if I have a List[Int]:

scala> Json.arr( List(1,2,3) )
res22: play.api.libs.json.JsArray = [[1,2,3]] // not what I wanted

I attempted to pass the List[Int] as var-args (if that's the right term):

scala> Json.arr( List(1,2,3): _* )
<console>:18: error: type mismatch;
 found   : List[Int]
 required: Seq[play.api.libs.json.Json.JsValueWrapper]
       Json.arr( List(1,2,3): _* )
                     ^

But that did not work.

Then, I tried to create a List[JsValueWrapper], and then pass that, via var-args, to Json#arr:

scala>  List(1,2,3).map(Json.toJsFieldJsValueWrapper)
<console>:18: error: No Json serializer found for type T. Try to implement an implicit Writes or Format for this type.
        List(1,2,3).map(Json.toJsFieldJsValueWrapper)
                             ^

Although that failed, the following works when applied to a single Int:

scala> Json.toJsFieldJsValueWrapper(1)
res27: play.api.libs.json.Json.JsValueWrapper = JsValueWrapperImpl(1)

scala> Json.arr(res27)
res28: play.api.libs.json.JsArray = [1]

How can I pass a List[Int] into Json.arr to get an output of [1,2,3], i.e. a JsArray consisting of three JsNumber's?

Upvotes: 0

Views: 104

Answers (2)

Michael Zajac
Michael Zajac

Reputation: 55569

You could use Json.toJson, validate as a JsArray, or return an empty one if invalid:

scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)

scala> Json.toJson(list).validate[JsArray].getOrElse(JsArray())
res6: play.api.libs.json.JsArray = [1,2,3]

You could also modify your lambda slightly with Json.arr:

scala> Json.arr(list.map(Json.toJsFieldJsValueWrapper(_)): _*)
res10: play.api.libs.json.JsArray = [1,2,3]

It seems as though without the parentheses, the compiler is having trouble inferring what T is. This is because the compiler tries to resolve the implicit before eta-expanding the anonymous function, so it doesn't know what argument will be passed to Json.toJsFieldJsValueWrapper yet. Json.toJsFieldJsValueWrapper(_) is fundamentally different because it expands to a slightly different Function1:

 x => Json.toJsFieldJsValueWrapper(x)

Here the compiler knows that x will be an Int, so the implicit Writes[Int] is resolved.

Upvotes: 4

Eric
Eric

Reputation: 1114

How about just using Json.toJson and casting to a JsArray (if you need to)?

scala> Json.toJson(List(1,2,3)).as[JsArray]
res0: play.api.libs.json.JsArray = [1,2,3]

Upvotes: 0

Related Questions