hotmeatballsoup
hotmeatballsoup

Reputation: 595

Parsing nested JSON values with Lift-JSON

Scala 2.12 here trying to use Lift-JSON to parse a config file. I have the following myapp.json config file:

{
  "health" : {
    "checkPeriodSeconds" : 10,
    "metrics" : {
      "stores" : {
        "primary" : "INFLUX_DB",
        "fallback" : "IN_MEMORY"
      }
    }
  }
}

And the following MyAppConfig class:

case class MyAppConfig()

My myapp.json is going to evolve and potentially become very large with lots of nested JSON structures inside of it. I don't want to have to create Scala objects for each JSON object and then inject that in MyAppConfig like so:

case class Stores(primary : String, fallback : String)
case class Metrics(stores : Stores)
case class Health(checkPeriodSeconds : Int, metrics : Metrics)
case class MyAppConfig(health : Health)

etc. The reason for this is I'll end up with "config object sprawl" with dozens upon dozens of case classes that are only in existence to satisfy serialization from JSON into Scala-land.

Instead, I'd like to use Lift-JSON to read the myapp.json config file, and then have MyAppConfig just have helper functions that read/parse values out of the JSON on the fly:

import net.liftweb.json._

// Assume we instantiate MyAppConfig like so:
//
// val json = Source.fromFile(configFilePath)
// val myAppConfig : MyAppConfig = new MyAppConfig(json.mkString)
//
class MyAppConfig(json : String) {
  implicit val formats = DefaultFormats

  def primaryMetricsStore() : String = {
    // Parse "INFLUX_DB" value from health.metrics.stores.primary
  }

  def checkPeriodSeconds() : Int = {
    // Parse 10 value from health.checkPeriodSeconds
  }
}

This way I can cherry pick which configs I want to expose (make readable) to my application. I'm just not following the Lift API docs to see how this strategy is possible, they all seem to want me to go with creating tons of case classes. Any ideas?

Upvotes: 0

Views: 1588

Answers (1)

Antot
Antot

Reputation: 3964

Case classes are not mandatory for extracting data from JSON. You can query the parsed tree and transfrom data according to your needs. The values from the example can be extracted as follows:

import net.liftweb.json._

class MyAppConfig(json : String) {
  private implicit val formats = DefaultFormats

  private val parsed = parse(json)

  def primaryMetricsStore() : String = {
    (parsed \ "health" \ "metrics" \ "stores" \ "primary").extract[String]
  }

  def checkPeriodSeconds() : Int = {
    (parsed \ "health" \ "checkPeriodSeconds").extract[Int]
  }

}

The original doc provides all the details.

Upvotes: 2

Related Questions