3

I am attempting to produce JSON in a Scala app using json4s. Fairly straight forward, Here's some sample value I put together to test it in my Scalatra app:

import org.json4s._
import org.json4s.JsonDSL._


object JsonStub {
    val getPeople = 
        ("people" ->
            ("person_id" -> 5) ~
            ("test_count" -> 5))

}

In my controller, I simply have:

import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.{DefaultFormats, Formats}

class FooController(mongoDb: MongoClient)(implicit val swagger: Swagger) extends ApiStack with NativeJsonSupport with SwaggerSupport {

get ("/people", operation(getPeople)) {
        JsonStub.getPeople
    }   

}

The output I'm seeing in the browser however, is the following:

{
  "_1": "people",
  "_2": {
    "person_id": 5,
    "test_count": 5
  }
}

Any clue where the _1 and _2 keys are coming from? I was expecting this output instead:

{
  "people":{
    "person_id": 5,
    "test_count": 5
  }
}
randombits
  • 47,058
  • 76
  • 251
  • 433

1 Answers1

5

What you're seeing in the output is a reflectively serialized tuple, which has fields _1 and _2. This is because the return type that the compiler has inferred for JsonStub.getPeople is Tuple2[String, JObject].

The json4s DSL uses implicit conversions to turn values like the tuple into a JValue. But, if you don't tell the compiler you wanted a JValue, it won't apply the conversion.

Ideally, this would result in a compile error, because you tried to produce JSON from something that isn't the right type. Unfortunately, because your web framework assumes you want to fall back to reflection-based serialization, it means there is another way to turn the tuple into JSON, which isn't what you wanted.

If you explicitly tell the compiler that you want a JValue and not a Tuple2, the DSL's implicit conversion will be applied in the correct place.

val getPeople: JValue = 
    ("people" ->
        ("person_id" -> 5) ~
        ("test_count" -> 5))
Ben James
  • 121,135
  • 26
  • 193
  • 155
  • That did it Ben, thank you so much. Any tips for how I could have figured this one out without posting here first? :-) There is probably a way to default all of my values to JValue here also, just not entirely sure how. – randombits Jul 08 '13 at 19:52
  • My pro tip would be to not use Scalatra, if you want type-safe development. Other than that, it's always a good idea to specify return types for the public members of an API, *especially* when relying on implicits. – Ben James Jul 08 '13 at 20:14
  • 3
    Is there a way to tell json4s to make the conversion explicitly? I'm running into the same thing and I'd rather not have to litter up my model classes with `JValues`. – David Moles Nov 23 '13 at 00:08