Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala 2.10, its impact on JSON libraries and case class validation/creation

Tags:

In Scala 2.10 apparently we're getting improved reflection.

How will this impact lift-json, jerkson, sjson and friends? Furthermore, can we expect in the not too distant future a built-in JSON language feature a la Groovy's excellent GSON in Scala?

The reason I ask is that I would dearly love to do:

case class Foo(a: String, b: Int, bar: Bar) case class Bar(c: Int) val foo = Foo("hey", 10, Bar(23)) val json = foo.toJson 

without hoop jumping (i.e. boilerplate-ish prep work), even with arbitrarily complex object graphs. Perhaps I'm asking way too much, but one can always dream. Please shatter my 2.10 dreams or enlighten me as to what new avenues are opening with the highly anticipated release of Scala.Next

Also, in regard to case classes, it seems for validation/creation, scalaz validation is the go-to weapon of choice. It seems quite wonderful, acting as a safe proxy for object creation or as an error collector. As a Scewbie, however, I find scalaz somewhat challenging, and am resisting the F-ing dark side despite its obvious power ;-)

At any rate, the point here is, with 2.10 reflection we should be able to bind at runtime the fields from say, a form post, to the properties of a case class and perform basic validation based on property type alone (i.e. will not have to specify separate validation logic that specifies property foo must be a String since its type is already defined in the case class upon which we can now properly reflect)

So, brave new world cometh, or existing tools are the mainstay for the foreseeable future?

like image 471
virtualeyes Avatar asked Mar 07 '12 22:03

virtualeyes


People also ask

What is the best JSON library for Scala?

rapture’s json library is the ultimate Scala JSON library. It doesn’t really do anything with JSON itself, instead, it abstracts over the following JSON libraries (which it calls backends ): Jawn Lift Play Scala standard library JSON

What is OS-lib and ujson in Scala?

os-lib and ujson make it easy to read and write JSON files with Scala. It’s painful to work with JSON and Scala without these libraries. Read this article or Hands on Scala Programming to learn more details about how ujson is implemented and other use cases.

What is @json4s in Scala?

json4s is a bit like slf4j in the sense that it tries to unite all kind of rogue libraries serving the same purpose by providing a common interface. But not every library uses it, which means that chances are high that your project will contain json4s in addition to another (few) Scala JSON libraries.

What are the benefits of using case class in Scala?

It has a by default hashCode implementation. The one of the topmost benefit of Case Class is that Scala Compiler affix a method with the name of the class having identical number of parameters as defined in the class definition, because of that you can create objects of the Case Class even in the absence of the keyword new.


2 Answers

Forewords

Let me give a different solution that doesn't rely on any Java based library but only a pure Scala one.

Actually, as discussed in the comments of @Steve's results Play 2's scala version was using Jerkson for de/serializing Json to domain model. Where Jerkson is a DSL wrapper around a very good Java library for handling Json.

Answer

The above wasn't answering your question, since you were asking if it has been envisioned to used the reflection and the macro features of Scala 2.10 to ease this task!!!! By eliminating most boilerplates.

And it was a very good thought in fact because from the Play 2.1 version, the Json Scala API is not using Jerkson anymore but it's own mechanism.

This mechanism is in fact taking advantages of this new 2.10 version of Scala by introducing a brand new API based on two things:

  • a functional construction (Applicative Builder) adapted to be able to Read and Write Json or Domain instances. These builders are used to glue altogether combinators (for both read or write) in order to define coarse grained structured (like we do with Parser Combinators)
  • a bunch of macros that are able to discover which combinators are implicitly available and will construct complex ones for Case Classes (or at least types that have apply and unapply methods).

In the end of the day, here is what we could do by using this API:

import play.api.libs.json._ import play.api.libs.functional.syntax._  case class Person(name: String, age: Int, lovesChocolate: Boolean)  implicit val personReads = Json.format[Person] //a format is a Reader and a Writer  //this format will be implicitly used by the following from/toJson functions val person:JsResult[Person] = Json.fromJson(json) //JsResult is like JsSucces/JsError val jsObject = Json.toJson(person) 

code copied and adapted from: JSON Inception (Based on Scala 2.10 Macros)

A little note: the new API is even smart enough to be able to validate a "read" by accumulating errors...

References

There are a series of blogs from @mandubian that I'd recommend from here, because they are very enlightening it!

  • JsPath & Reads Combinators: http://mandubian.com/2012/09/08/unveiling-play-2-dot-1-json-api-part1-jspath-reads-combinators/
  • Writes/Format Combinators: http://mandubian.com/2012/10/01/unveiling-play-2-dot-1-json-api-part2-writes-format-combinators/
  • JSON Transformers: http://mandubian.com/2012/10/29/unveiling-play-2-dot-1-json-api-part3-json-transformers/
  • JSON Inception (Based on Scala 2.10 Macros) : http://mandubian.com/2012/11/11/JSON-inception/

Final note

What is sad is that the modularization of Play 2... doesn't allow us to use this API alone! So, it should be used from the play lib as a whole :/ This might change in the future...

EDIT

And the future is getting closer now, since Pascal has this repo enabling us to use the play-json API.

So, one can use this repo until Play 2.2 will be released. Indeed, this version will be completely decoupled with several APIs like json or iteratees, and thus, we'll be able to use the playframework repo directly.

like image 58
Andy Petrella Avatar answered Oct 18 '22 05:10

Andy Petrella


Jerkson handles your use case today!

Json.generate(foo) 

It also supports streaming reads and writes which we use extensively in production.

Json.generate(foo, outputStream) Json.parse[Foo](inputStream) 

We originally used lift-json but its lack of streaming support for case classes made it unusable for reading and writing large json documents. Jerkson is also super fast and handles nested case classes perfectly.

like image 33
Steve Avatar answered Oct 18 '22 04:10

Steve