tesnik03 tesnik03 - 2 months ago 5x
Scala Question

meta-programming to parse json in scala

I need some hints to write a scala program that could read json file and create a case class at run time. As an example if we have json class like -

name:{datatype:String, null:false}
age:{datatype:Int, null:true}
Address:{city: {datatype: String, null:true}, zip: {datatype: String, null:false}}

and this should create class like

case class Employ(name: String, age: Option[Int], address: Address}
case class Address(city: Option[String], zip:String}

would it be possible to do it in scala?


Yes, you can easily achieve this using TreeHugger. I did a similar thing for one of my work projects.

Below is a toy example which produces a Scala Akka Actor class. It needs to be cleaned up but, hopefully, you get the idea:

import argonaut.Argonaut._
import argonaut._
import org.scalatest.FunSuite
import treehugger.forest._
import definitions._
import treehuggerDSL._

class ConvertJSONToScalaSpec extends FunSuite {

  test("read json") {

    val input =
        |  "rulename" : "Rule 1",
        |  "condition" : [
        |    {
        |      "attribute" : "country",
        |      "operator" : "eq",
        |      "value" : "DE"
        |    }
        |    ],
        |  "consequence" : "route 1"

    val updatedJson: Option[Json] = input.parseOption

    val tree =
        CLASSDEF(sym.c).withParents(sym.d, sym.e) :=
            IMPORT(sym.consignorImport, "_"),
            DEFINFER(sym.methodName) withFlags (Flags.OVERRIDE) := BLOCK(
              CASE(sym.f DOT sym.methodCall APPLY (REF(sym.mc))) ==>
                  sym.log DOT sym.logmethod APPLY (LIT(sym.logmessage)),
                  (IF (sym.declaration DOT sym.header DOT sym.consignor DOT sym.consignoreTID ANY_== LIT(1))
                    THEN (sym.sender APPLY() INFIX ("!", LIT(sym.okcm)))
                    (sym.sender APPLY() INFIX ("!", LIT(sym.badcm)))
      ) inPackage (sym.packageName)    

Essentially all you need to do is work out how to use the TreeHugger macros; each macro represents a specific keyword in Scala. It gives you a type-safe way to do your meta-programming.

There's also Scala Meta but I haven't used that.