4

I have the following data structure:

val jsonStr = """
     {
      "data1": {
        "field1": "data1",
        "field2": 1.0,
        "field3": true
      },
      "data211": {
        "field1": "data211",
        "field2": 4343.0,
        "field3": false
      },
      "data344": {
        "field1": "data344",
        "field2": 436778.51,
        "field3": true
      },
      "data41": {
        "field1": "data41",
        "field2": 14348.0,
        "field3": true
      }
    }
  """

I want extract it. Here is what I'm doing without any luck:

#1. 
case class Fields(field1: String, field2: Double, field3: Boolean)
json.extract[Map[String, Map[Fields, String]]]
//org.json4s.package$MappingException: Do not know how to convert JBool(true) 
//into class       java.lang.String

#2.
json.extract[Map[String, Map[String, Fields]]
//java.lang.InternalError: Malformed class name


#3.
json.extract[Map[String, Map[String, Any]]]
//org.json4s.package$MappingException: No information known about type

#4.
json.extract[Map[String, Map[String, String]]]
//org.json4s.package$MappingException: Do not know 
//how to convert JBool(true) into class java.lang.String

How do I do that then?

P.S. -- actually, that's https://github.com/json4s/json4s but it's doesn't really matter since lift has the same API regarding json extracting.

UPDATE: It probably will require to use transform method. How will I use it?

val json = parse(jsonStr) transform { 
  case //.... what should be here to catch JBool -- "field3"?
}

UPDATE2:

#5
json.extract[Map[String, Map[String, JValue]]]
// Works! but it's not what I'm looking for, I need to use a pure Java/Scala type
Alan Coromano
  • 24,958
  • 53
  • 135
  • 205
  • `json.extract[Map[String, Fields]]` seems to work for me. The double `Map` structure doesn't. What was the second map looking to capture? – jcern Jun 07 '13 at 00:36
  • @jcern it doesn't work, I just checked. – Alan Coromano Jun 07 '13 at 00:58
  • Hmm, then there seems to be a difference between the lift parser and `json4s`, because the lift version seems to work for me (or I did something additional that I didn't realize). Perhaps it has something to do with the formats it is using to extract. – jcern Jun 07 '13 at 01:02
  • @jcern what does it by "seems"? are you trying to guess? – Alan Coromano Jun 07 '13 at 01:08
  • What I mean by "seems" is that I am not sure if it is what you were looking for, hence the statement about doing something else (and my question about what the double Map was looking to capture). Anyway, I posted the REPL output for you. It uses the Lift JSON parser - hopefully it helps. – jcern Jun 07 '13 at 01:49
  • Just to add, for those who have come here for json values like myjson = [{ "field1": "data1", "field2": 1.0, "field3": true },{ "field1": "data2", "field2": 2.0, "field3": false }] , use parse(myjson).extract[List[Map[String,Any]]], follow this link which basically converts map object to case class object https://stackoverflow.com/questions/20684572/scala-convert-map-to-case-class and then use toString to convert to string and toString.toBoolean to convert to boolean for the respective fields. – sdinesh94 Aug 22 '17 at 20:55

1 Answers1

11
scala> val jsonStr = """
     |      {
     |       "data1": {
     |         "field1": "data1",
     |         "field2": 1.0,
     |         "field3": true
     |       },
     |       "data211": {
     |         "field1": "data211",
     |         "field2": 4343.0,
     |         "field3": false
     |       },
     |       "data344": {
     |         "field1": "data344",
     |         "field2": 436778.51,
     |         "field3": true
     |       },
     |       "data41": {
     |         "field1": "data41",
     |         "field2": 14348.0,
     |         "field3": true
     |       }
     |     }
     |   """
jsonStr: java.lang.String = 
"
     {
      "data1": {
        "field1": "data1",
        "field2": 1.0,
        "field3": true
      },
      "data211": {
        "field1": "data211",
        "field2": 4343.0,
        "field3": false
      },
      "data344": {
        "field1": "data344",
        "field2": 436778.51,
        "field3": true
      },
      "data41": {
        "field1": "data41",
        "field2": 14348.0,
        "field3": true
      }
    }
  "

scala> import net.liftweb.json._
import net.liftweb.json._

scala> implicit val formats = DefaultFormats
formats: net.liftweb.json.DefaultFormats.type = net.liftweb.json.DefaultFormats$@361ee3df

scala> val json = parse(jsonStr)
json: net.liftweb.json.package.JValue = JObject(List(JField(data1,JObject(List(JField(field1,JString(data1)), JField(field2,JDouble(1.0)), JField(field3,JBool(true))))), JField(data211,JObject(List(JField(field1,JString(data211)), JField(field2,JDouble(4343.0)), JField(field3,JBool(false))))), JField(data344,JObject(List(JField(field1,JString(data344)), JField(field2,JDouble(436778.51)), JField(field3,JBool(true))))), JField(data41,JObject(List(JField(field1,JString(data41)), JField(field2,JDouble(14348.0)), JField(field3,JBool(true)))))))


scala> case class Fields(field1: String, field2: Double, field3: Boolean)
defined class Fields

scala> json.extract[Map[String, Fields]]
res1: Map[String,Fields] = Map(data1 -> Fields(data1,1.0,true), data211 -> Fields(data211,4343.0,false), data344 -> Fields(data344,436778.51,true), data41 -> Fields(data41,14348.0,true))
jcern
  • 7,798
  • 4
  • 39
  • 47