Noise-free JSON processing with Scala
I'm coming from a dotnet land, but recently have been looking at the possibilities of alternative programming languages. Nothing really serious, just some bits here and there. Recently I've discovered Scala and I'm pretty fascinated with it. Despite non-deterministic tinkering, I've done some intermediate checks of stuff that is important for me in C# and I feel rather satisfied: functional notions - tick, ad-hoc polymorphism - tick, annotations - tick, reflection and codegen - tick.
Now I'm thinking about how one would program an analogue of JSON processing library I've implemented in C# 4.0 with the help of DLR and "dynamic" syntactic sugar. Here's the feature set I'm looking for:
- Convenient browsing and construction of raw JSON.
- Automatic conversion between JSON and native objects/collections (in its general form the problem is unsolvable, though one can define conventions that will work 95% of the time - and that's fine for me).
New features of C# 4.0 kinda rock here, since they let me override member access and type casts to perform completely custom logic (if a variable in C# 4.0 is typed as "dynamic", then anything you do with it will be compiled into calls to programmer-defined met开发者_如何学运维hods with reasonable default behaviour - see DynamicMetaObject.BindXXX methods at MSDN for more info). E.g. I've overriden type casts to serialize/deserialize .NET objects and member accesses to manage raw JSON, so that I can write the following code:
var json = Json.Get("http://some.service");
if (json.foo) Console.WriteLine((Foo)json.foo);
json.bars = ((List<Bar>)json.bars).DoSomething();
Of course, this is not ideal, since dynamic binding in C# 4.0 has problems with extension methods and type inference, and, moreover, the code still feels rather heavyweight. But anyways, this is much better than using all those ((JsonObject)json["quux"])["baz"] I've used to in c# 3.5.
Some basic research shows that Scala doesn't have dedicated language features that support late binding. However, there are so many tricks that maybe they can be used together to create a bearable emulation of the code shown above (or even to be better - I almost sure that this is possible). Could you, please, advise me something here?
A useful JSON library for Scala is lift-json, which is a standalone component of the Lift Web Framework.
https://github.com/lift/framework/tree/master/core/json
It supports extraction to classes, parsing and a DSL for creating JSON.
The page I linked to has a comprehensive tutorial, so I won't just copy and paste it.
You should definitely have a look at sjson. Here -> sjson on github I'm using the Type class based implementation, which you can peruse here -> some examples If you have a jaunt through the code, there's some really interesting scala tricks. This should give you what you're looking for in regards to #2. SJSON wraps dispatch-json which I believe provides integration to lift-json (mentioned above). Both dispatch-json/lift-json should give you what you're looking for in #1. For what its worth I've been using sjson in a large project and its going swimmingly. And the gentleman behind the project has been pretty amazing and supports the project very well.
I've floated between using lift-json
and various variants of sjson
(e.g. dabasishg/sjson) and more recently Jerkson
(a Scala wrapper on Jackson).
For the purposes of object serialization and deserialization I keep on finding Jerkson
to require the least tweaking to get a job done, for example, I've just been coding a simple object serialisation with a case class
that looks like this:
import org.joda.time.LocalDate
case class UserStatus(subscriptionEndDate: LocalDate = null)
I had various errors with both lift-json
and sjson
but jerkson
just worked with:
import com.codahale.jerkson.Json
val jsonString = Json.generate(statusObject)
and
val newObject = Json.parse[UserStatus](jsonString)
As others have pointed out, there are many choices. Beyond ones mentioned, most Java JSON processing libraries should work with Scala, too, with varying levels of (in)convenience for non-Java JVM languages (like Scala, Clojure, Groovy).
Ones that are most powerful in terms of data binding are Jackson, GSON and FlexJSON. One possibility is to check them out, and see if you can help improve interoperability -- Scala for example has a number of "exotic" data types that would benefit from explicit handling (above and beyond handling of 'standard' java objects that libs support).
If you wanna some thing really dynamic in scala, here it is: http://www.scala-lang.org/api/current/scala/Dynamic.html
A marker trait that enables dynamic invocations. Instances x of this trait allow calls x.meth(args) for arbitrary method names meth and argument lists args. If a call is not natively supported by x, it is rewritten to x.applyDynamic("meth", args).
As of scala 2.9, scalac must receive the -Xexperimental optional for Dynamic to receive this treatment.
Now, it's a experimental feature, and not as strong as the .NET DLR.
Casbah the scala-mongodb-driver has tried it.
interestinly enough the code to do this in scala is WAY more involved than that of Java.. none of those answers give a noise free solution like the Java Jackson library except for Jerkson which wraps around Jackson.
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(new File("user.json"), User.class); //to parse
mapper.writeValue(new File("user-modified.json"), user); //to produce
精彩评论