Search code examples
jsonscalaspray-json

how do i convert json with mixed type values to json with scala and json spray


I tried the tutorial of json spray but i have a different string where one value is a string and the other one is a list. How do i convert the following string into a json object where each key is either a list or a string?

source = """{ "some": "JSON source", "kuku":["fu"] }"""

I wrote a short snipped of code but cannot continue from here:

val source = """{ "some": "JSON source", "kuku":["fu"] }"""
val jsonAst = source.asJson
val kuku = jsonAst.convertTo[?]
println(kuku)

If i cannot, how do i get the value of the key some(hopefully without regular expression) I would prefer to avoid creating a specific object for it, because there are certain keys which can change.

Thanks, David


Solution

  • You can convert the entire object to a map to an Either:

    val jsonMap = jsonAst.convertTo[Map[String, Either[String, List[String]]]]
    

    And then:

    scala> println(jsonMap)
    Map(some -> Left(JSON source), kuku -> Right(List(fu)))
    

    The Either part explicitly models the fact that you don't know at compile-time which kind of value you'll get when you look up a key. There are lots of introductions to the idea of Either in Scala, but in short you can use it like this:

    val some: String = jsonMap("some").left.getOrElse(
      ??? /* Provide a default value, throw an exception, etc. */
    )
    
    val kuku: List[String] = jsonMap("kuku").right.getOrElse(
      ??? /* Provide a default value, throw an exception, etc. */
    )
    

    Or, even better, handle the fact that the key might not exist at the same time:

    val some: String = jsonMap.get("some").flatMap(_.left.toOption).getOrElse(
      ??? /* Provide a default value, throw an exception, etc. */
    )
    

    Alternatively you could navigate to the "kuku" field and then convert:

    val kuku = jsonAst.asJsObject.getFields("kuku").headOption.map(
      _.convertTo[List[String]]
    )
    

    And then:

    scala> kuku
    res0: Option[List[String]] = Some(List(fu))
    

    I personally find the first approach a little cleaner.