A minimalistic JSON parser for scala. Its goals:
The parser is hand-crafted, resulting in very good performance. It's up to par with Jackson, more than 350 times faster than the default json parser (that shipped with scala until 2.10), and more than 15 times faster than the spray-json parser. (Running the tests will report timing information.)
The parser streams its result into a json handler. The handler gets events from the parser and can act accordingly. It allows for memory-efficient processing of large data sets.
The core parser is not tied to a particular JSON AST (abstract syntax tree). Through the streaming interface, any AST can be built. The parser currently ships with a spray-json builder, more will follow.
The json-parser can be obtained from maven central, cross-built against scala 2.10 and 2.11:
"org.scalastuff" %% "json-parser" % "2.0.2"
A parser is instantiated by providing a handler. Alternatively, a specialized version can be used, like the SprayJsonParser.
import org.scalastuff.json.JsonParser
val parser = new JsonParser(new MyJsonHandler)
The parser has three parse overloads:
def parse(reader: Reader)
def parse(source: String)
def parse(source: Array[Char])
The Reader
overload allows streaming some JSON input into the parser. The document will be processed character-by-character, the input will not be read into memory.
The String
and Array[Char]
overloads are wrappers around the Reader
overload, but they use an optimized reader, FastStringReader. Compared to using java.io.StringReader
and java.io.CharArrayReader
, expect a speedup of nearly 50%.
Note that a parser instance is NOT thread safe. It can be re-used though, and one is advised to do so.
The parser ships with a built-in spray parser, targeting the spray-json AST:
import spray.json.JsValue
import org.scalastuff.json.spray.SprayJsonParser
val parser = new SprayJsonParser
val result: JsValue = parser.parse(someJson)
It also has an 'object' interface, that adds some convenience. It creates a parser instance on each invocation, which can be useful in a multi-threaded environment:
val result: JsValue = SprayJsonParser.parse(someJson)
Note: to use this parser in the context of spray.io (e.g. in spray-routing), one should use an alternative implementation of spray.httpx.SprayJsonSupport
. Providing such an implementation is out of scope for this project though.
A JsonHandler is a call-back interface for parse events, comparable to SAX for XML.
Using a Reader
in combination with a custom handler allows for true streamed JSON processing.
The SprayJsonBuilder is probably a good starting point when writing a custom handler.
The JsonPrinter pretty-prints json to a given writer. It is a handler, so it can be fed to the parser. The following example illustrates how file data can can be pretty-printed and directly streamed to an output stream:
val reader = new FileReader("data.json")
val writer = new OutputStreamWriter(System.out)
val parser = new JsonParser(new JsonPrinter(writer))
parser.parse(reader)
writer.close()
- Allow for asynchronous, 'reactive' streaming. See issue #3.
This software is released under the Apache License, Version 2.0