0

I have a json format that consists of map -> map -> ... -> int for an arbitrary number of maps per key. The keys are always strings and the leaf types are always ints. The depth of the map structure varies per key in the map. For example, key "A" could be type Map[String, Int] and key "B" could be type Map[String, Map[String, Int]]. I know I can parse this format successfully as Map[String, Any], but I'm trying to preserve the types to make these structures easier to merge later in the code.

I can't seem to define my nested structure in such a way as to not throw an error on the json4s extract. I'm not quite sure if the problem is in my structure definition or if I'm not doing the json extract correctly.

Here is the code

sealed trait NestedMap[A]
case class Elem[A](val e : A) extends NestedMap[A]
case class NMap[A](val e : Map[String, NestedMap[A]]) extends NestedMap[A]
// XXX this next line doesn't seem to help or hurt
case class Empty extends NestedMap[Nothing]

implicit val formats = DefaultFormats
val s = "{\"1\": 1, \"2\": 1, \"3\": {\"4\": 1}}"

val b = parse(s).extract[NMap[Int]] 

Here is the error that always comes up

org.json4s.package$MappingException: No usable value for e
Expected object but got JNothing

Do I need to add another value that extends NestedMap? Am I going about this entirely wrong? Any help is much appreciated.

trent
  • 1
  • 1

1 Answers1

1

By default, a tree like yours is expanded to to a different json.

import org.json4s._
import org.json4s.native.Serialization
import org.json4s.native.Serialization.{read, write}
import org.json4s.native.JsonMethods._

implicit val formats = Serialization.formats(NoTypeHints)

sealed trait Elem
case class Leaf(val e:Int) extends Elem
case class Tree(val e:Map[String, Elem]) extends Elem

scala> val t = Tree(Map("1"->Leaf(1),"2"->Leaf(2),"3"->Tree(Map("4"->Leaf(4)))))
t: Tree = Tree(Map(1 -> Leaf(1), 2 -> Leaf(2), 3 -> Tree(Map(4 -> Leaf(4)))))
scala> write(t)
res0: String = {"e":{"1":{"e":1},"2":{"e":2},"3":{"e":{"4":{"e":4}}}}}
scala> val jt = parse(res0)
jt: org.json4s.JValue = JObject(List((e,JObject(List((1,JObject(List((e,JInt(1))))), (2,JObject(List((e,JInt(2))))), (3,JObject(List((e,JObject(List((4,JObject(List((e,JInt(4))))))))))))))))


scala> val s = """{"1":1,"2":2, "3":{"4":1}}"""
s: String = {"1":1,"2":2, "3":{"4":1}}
scala> val st = parse(s)
st: org.json4s.JValue = JObject(List((1,JInt(1)), (2,JInt(2)) (3,JObject(List((4,JInt(1)))))))
Ashalynd
  • 12,363
  • 2
  • 34
  • 37
  • I understand why my trait is wrong now in that it can't find the "e". Thanks. I'm still confused on how to define a type for s though. I'm not generating this json, so I can't modify it to include the "e". – trent Oct 07 '14 at 06:08