I had created this little thing a while ago, to manipulate json via simple Map and List and I keep finding uses for it all the time, like here's how to transform a fairly complicated model into JSON:
/** simple json like representation of domain for browsing */
def tojmap = {
Map("name"->name,
"classes" -> classes.values.toList.map{c=>
Map(
"name"->c.name,
"parms" -> c.parms.map{p=>
Map(
"name"->p.name,
"t" -> p.ttype
)
},
"assocs" -> c.assocs.collect{
case a : A => Map(
"aname" -> a.a,
"zname" -> a.z,
"aRole" -> a.aRole,
"zRole" -> a.zRole,
"assocClass"-> a.ac.map(_.name).mkString
)
case d : D => Map(
"roles" -> d.roles.map{t=>Map("className"->t._1, "role"->t._2)},
"assocClass" -> d.ac.map(_.name).mkString
)
}
)},
"objects" -> objects.values.toList.map{c=>
Map(
"name" -> c.name,
"parms" -> c.parms.toList.map{p=>
Map(
"name" -> p.name,
"value" -> p.value
)
}
)}
)
}
val toString = js.tojsons(tojmap) // see link to js below
Cool scala, right? Because most models contain aggregations via Map/Seq/List, you can easily read this resulting code: it matches the originating structure, it's easy to look at, almost like a template. I like it!
The scala language allows this not only with the simple tuple notation and being functional but via pattern matching as well (collect
). We could certainly use filter()
to cut out private fields etc.
The final manipulation of the generated Map+List dynamic structure is with a simple utility class - js utilities. See details at the bottom.
If we had to create JSONObject and JSONArray things, it would have been more complicated and not as good looking or easy to read. Perhaps not the most efficient way to get a JSON String from a random structure, but my time is more important than some CPU's time.
If you like simple things, look also at snakked.
The easiest thing I have ever seen though, I must admit, is salat's grater: grater[Company].asObject(dbo)
but I had some issues using it on random objects...
It's a stand-alone file, just copy and use or depend on the entire snakked-0.6.7-SNAPSHOT. The main methods are:
tojson
to turn maplists into JSON objectstojsons
to pretty print it as a string insteadfromObject
to get a maplist from JSON objectsparse
helperjt
- simple json transformations, this is cool too, see jsmap - simple json transformationsNote that the code is not the most optimal - I was having fun originally, so you see stuff like " " * 5
.
val snakk = "com.razie" %% "snakked" % "0.6.7-SNAPSHOT"
The issue was messing with JSON documents. Create JSON docs to return from REST end points etc. Also, parsing JSON back into something useful.
I keep forgetting interfaces and the JSON interfaces are not that simple, what with JSONObject, JSONArray... really complicated, right? There's a play parser, a json, a spray - etc. Which of these should I hardcode straight into my model? Or in serializer classes?
So, I obviously had to make up my own, of course :). I went back to the crux of JSON: javascript object notation. An object is really a map and there's arrays and values and other maps.
Hence, the jsmap
or a simple Map[_ , _]
, where the values can be Map[_ , _]
or List[_]
or simple strings (or anything with a toString()
method, of course.
Turning this to Json is straight forward and so is extracting it from an actual JSON document, hence the js utilities.
The other alternative I can think of would be to use a templating engine, one based on scala (like a play template). Lots of advantages of course... but one disadvantage would be that it will create the String of the json directly and you can't apply any more transformations - but often that's just what you'd need and, because the templating support is more comprehensive, perhaps a little better.