1

Given a parsed (via json4s) json string e.g. the following org.json4s.JValue:

val data: JValue = parse("""{
    "important_field" : "info",
    "some_junk" : 12345,
    "interesting_stuff" : {
        "pi" : 3.14,
        "e" : 2.72
    }
}""")

I can selectively extract the information I need:

case class Data(important_field: String) 
val extracted: Data = data.extract[Data]

giving extracted: Data = Data(info). Further, I can extract information from a nested json object with another case class:

case class Stuff(pi: Double)
case class Data(important_field: String, interesting_stuff: Stuff)
val extracted: Data = data.extract[Data]

which gives me extracted: Data = Data(info,Stuff(3.14)). But now, if I want to access fields in the nested object, I need to use Stuff, my inner case class:

val pi: Double = extracted.interesting_stuff.pi

I'd prefer to drop the nesting, so Data is flat, i.e. I want to access the (originally) nested fields like this:

val pi: Double = extracted.pi

In this trivial case, using the nested class is not that painful, but when there are multiple levels of nesting it's frustrating to have to maintain that nesting in my object. Is there a typical approach for dealing with this? Some fancy Scala trick?

2 Answers 2

1

you can define a getter to the nested field in your outer case class

case class Data(important_field: String, interesting_stuff: Stuff) {
    def pi: Double = interesting_stuff.pi
}

// now you'll be able to write
val pi: Double = extracted.pi

the downside is that you have to do this by hand for each nested field you want to access easily

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. This solves one half of the issue, but I still need to create Stuff. Ideally I'd avoid that as well.
1

Nested json structures can be transformed before mapping json content to your own case class:

object NestedJsonSpec {
  case class Data(important_field: String, pi: Double)

  implicit val formats = DefaultFormats // Brings in default date formats etc.

  def extract(source: JsonInput) : Data = {
    parse(source).transformField({
      case JField("interesting_stuff", jv) => ("pi", jv \ "pi")
    }).extract[Data]
  }
}

As a result one does not have to define a nested case class Stuff.

Dependencies used in the code were:

scalaVersion := "2.11.8"

libraryDependencies ++= {
  Seq(
    "org.json4s" %% "json4s-ext" % "3.5.0",
    "org.json4s" %% "json4s-native" % "3.5.0",
    "org.scalatest" %% "scalatest" % "2.2.6" % Test
  )
}

Here is the related github project with the unit test.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.