What JSON library to use in Scala?

JsonScala

Json Problem Overview


I need to build a JSON string, something like this:

[
  { 'id': 1, 'name': 'John'},
  { 'id': 2, 'name': 'Dani'}
]

val jArray = JsArray();
jArray += (("id", "1"), ("name", "John"))
jArray += (("id", "2"), ("name", "Dani"))
println(jArray.dump)

I need to be able to add rows to the jArray, something like jArray += ...

What is the closest library/solution to this?

Json Solutions


Solution 1 - Json

Unfortunately writing a JSON library is the Scala community's version of coding a todo list app.

There are quite a variety of alternatives. I list them in no particular order, with notes:

  1. parsing.json.JSON - Warning this library is available only up to Scala version 2.9.x (removed in newer versions)
  2. spray-json - Extracted from the Spray project
  3. Jerkson ± - Warning a nice library (built on top of Java Jackson) but now abandonware. If you are going to use this, probably follow the Scalding project's example and use the backchat.io fork
  4. sjson - By Debasish Ghosh
  5. lift-json - Can be used separately from the Lift project
  6. json4s § ± - An extraction from lift-json, which is attempting to create a standard JSON AST which other JSON libraries can use. Includes a Jackson-backed implementation
  7. Argonaut § - A FP-oriented JSON library for Scala, from the people behind Scalaz
  8. play-json ± - Now available standalone, see this answer for details
  9. dijon - A handy, safe and efficient JSON library, uses jsoniter-scala under hood.
  10. sonofjson - JSON library aiming for a super-simple API
  11. Jawn - JSON library by Erik Osheim aiming for Jackson-or-faster speed
  12. Rapture JSON ± - a JSON front-end which can use 2, 4, 5, 6, 7, 11 or Jackson as back-ends
  13. circe - fork of Argonaut built on top of cats instead of scalaz
  14. jsoniter-scala - Scala macros for compile-time generation of ultra-fast JSON codecs
  15. jackson-module-scala - Add-on module for Jackson to support Scala-specific datatypes
  16. borer - Efficient CBOR and JSON (de)serialization in Scala

 = has not fixed security vulnerabilities, § = has Scalaz integration, ± = supports interop with Jackson JsonNode

In Snowplow we use json4s with the Jackson back-end; we've had good experiences with Argonaut too.

Solution 2 - Json

Lift-json is at version 2.6 and it works really well (and is also very well supported, the maintainer is always ready to fix any bugs users may find. You can find examples using it on the github repository

The maintainer (Joni Freeman) is always reachable on the Lift mailing list. There are also other users on the mailing list who are very helpful as well.

As @Alexey points out, if you want to use the library with other Scala version, say 2.11.x, change scalaVersion and use %% as follows:

scalaVersion := "2.11.5" 

"net.liftweb" %% "lift-json" % "2.6"

You can check the liftweb.net site to find out the latest version as time goes by.

Solution 3 - Json

I suggest using jerkson, it supports most basic type conversions:

scala> import com.codahale.jerkson.Json._

scala> val l = List( 
                 Map( "id" -> 1, "name" -> "John" ),
                 Map( "id" -> 2, "name" -> "Dani")
               )

scala> generate( l )

res1: String = [{"id":1,"name":"John"},{"id":2,"name":"Dani"}]

Solution 4 - Json

Number 7 on the list is Jackson, not using Jerkson. It has support for Scala objects, (case classes etc).

Below is an example of how I use it.

object MyJacksonMapper extends JacksonMapper
val jsonString = MyJacksonMapper.serializeJson(myObject)
val myNewObject = MyJacksonMapper.deserializeJson[MyCaseClass](jsonString)

This makes it very simple. In addition is the XmlSerializer and support for JAXB Annotations is very handy.

This blog post describes it's use with JAXB Annotations and the Play Framework.

http://krasserm.blogspot.co.uk/2012/02/using-jaxb-for-xml-and-json-apis-in.html

Here is my current JacksonMapper.

trait JacksonMapper {

  def jsonSerializer = {
    val m = new ObjectMapper()
    m.registerModule(DefaultScalaModule)
    m
  }

  def xmlSerializer = {
    val m = new XmlMapper()
    m.registerModule(DefaultScalaModule)
    m
  }

  def deserializeJson[T: Manifest](value: String): T = jsonSerializer.readValue(value, typeReference[T])
  def serializeJson(value: Any) = jsonSerializer.writerWithDefaultPrettyPrinter().writeValueAsString(value)
  def deserializeXml[T: Manifest](value: String): T = xmlSerializer.readValue(value, typeReference[T])
  def serializeXml(value: Any) = xmlSerializer.writeValueAsString(value)

  private[this] def typeReference[T: Manifest] = new TypeReference[T] {
    override def getType = typeFromManifest(manifest[T])
  }

  private[this] def typeFromManifest(m: Manifest[_]): Type = {
     if (m.typeArguments.isEmpty) { m.erasure }
     else new ParameterizedType {
       def getRawType = m.erasure

       def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray

       def getOwnerType = null
     }
  }
}   

Solution 5 - Json

Maybe I've late a bit, but you really should try to use json library from play framework. You could look at documentation. In current 2.1.1 release you could not separately use it without whole play 2, so dependency will looks like this:

val typesaferepo  = "TypeSafe Repo" at "http://repo.typesafe.com/typesafe/releases"
val play2 = "play" %% "play" % "2.1.1"

It will bring you whole play framework with all stuff on board.

But as I know guys from Typesafe have a plan to separate it in 2.2 release. So, there is standalone play-json from 2.2-snapshot.

Solution 6 - Json

You should check Genson. It just works and is much easier to use than most of the existing alternatives in Scala. It is fast, has many features and integrations with some other libs (jodatime, json4s DOM api...).

All that without any fancy unecessary code like implicits, custom readers/writers for basic cases, ilisible API due to operator overload...

Using it is as easy as:

import com.owlike.genson.defaultGenson_

val json = toJson(Person(Some("foo"), 99))
val person = fromJson[Person]("""{"name": "foo", "age": 99}""")

case class Person(name: Option[String], age: Int)

Disclaimer: I am Gensons author, but that doesn't meen I am not objective :)

Solution 7 - Json

Here is a basic implementation of writing and then reading json file using json4s.

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._
import java.io._
import scala.io.Source


object MyObject { def main(args: Array[String]) {
  
  val myMap = Map("a" -> List(3,4), "b" -> List(7,8))

  // writing a file 
  val jsonString = pretty(render(myMap))

  val pw = new PrintWriter(new File("my_json.json"))
  pw.write(jsonString)
  pw.close()

  // reading a file 
  val myString = Source.fromFile("my_json.json").mkString
  println(myString)

  val myJSON = parse(myString)

  println(myJSON)

  // Converting from JOjbect to plain object
  implicit val formats = DefaultFormats
  val myOldMap = myJSON.extract[Map[String, List[Int]]]

  println(myOldMap)
 }
}

Solution 8 - Json

Jawn is a very flexible JSON parser library in Scala. It also allows generation of custom ASTs; you just need to supply it with a small trait to map to the AST.

Worked great for a recent project that needed a little bit of JSON parsing.

Solution 9 - Json

Rapture seems to be missing in the list of the answers. It can be obtained from http://rapture.io/ and allows you (among other thing) to:

  • select JSON back-end, which is very useful if you already use one (in import)
  • decide if you work with Try, Future, Option, Either, etc. (also in import)
  • do a lot of work in a single line of code.

I don't want to copy/paste Rapture examples from it's page. A nice presentation about Rapture's features was given by Jon Pretty at SBTB 2014: https://www.youtube.com/watch?v=ka5-OLJgybI

Solution 10 - Json

@AlaxDean's #7 answer, Argonaut is the only one that I was able to get working quickly with sbt and intellij. Actually json4s also took little time but dealing with a raw AST is not what I wanted. I got argonaut to work by putting in a single line into my build.st:

libraryDependencies += "io.argonaut" %% "argonaut" % "6.0.1"

And then a simple test to see if it I could get JSON:

package mytest


import scalaz._, Scalaz._
import argonaut._, Argonaut._

object Mytest extends App {

  val requestJson  =
    """
    {
      "userid": "1"
    }
    """.stripMargin

  val updatedJson: Option[Json] = for {
    parsed <- requestJson.parseOption
  } yield ("name", jString("testuser")) ->: parsed

  val obj = updatedJson.get.obj
  printf("Updated user: %s\n", updatedJson.toString())
  printf("obj : %s\n", obj.toString())
  printf("userid: %s\n", obj.get.toMap("userid"))
}

And then

$ sbt
> run
Updated user: Some({"userid":"1","name":"testuser"})
obj : Some(object[("userid","1"),("name","testuser")])
userid: "1"

Make sure you are familiar with Option which is just a value that can also be null (null safe I guess). Argonaut makes use of Scalaz so if you see something you don't understand like the symbol \/ (an or operation) it's probably Scalaz.

Solution 11 - Json

You can try this: https://github.com/momodi/Json4Scala

It's simple, and has only one scala file with less than 300 lines code.

There are samples:

test("base") {
    assert(Json.parse("123").asInt == 123)
    assert(Json.parse("-123").asInt == -123)
    assert(Json.parse("111111111111111").asLong == 111111111111111l)
    assert(Json.parse("true").asBoolean == true)
    assert(Json.parse("false").asBoolean == false)
    assert(Json.parse("123.123").asDouble == 123.123)
    assert(Json.parse("\"aaa\"").asString == "aaa")
    assert(Json.parse("\"aaa\"").write() == "\"aaa\"")

    val json = Json.Value(Map("a" -> Array(1,2,3), "b" -> Array(4, 5, 6)))
    assert(json("a")(0).asInt == 1)
    assert(json("b")(1).asInt == 5)
}
test("parse base") {
    val str =
        """
          {"int":-123, "long": 111111111111111, "string":"asdf", "bool_true": true, "foo":"foo", "bool_false": false}
        """
    val json = Json.parse(str)
    assert(json.asMap("int").asInt == -123)
    assert(json.asMap("long").asLong == 111111111111111l)
    assert(json.asMap("string").asString == "asdf")
    assert(json.asMap("bool_true").asBoolean == true)
    assert(json.asMap("bool_false").asBoolean == false)
    println(json.write())
    assert(json.write().length > 0)
}
test("parse obj") {
    val str =
        """
           {"asdf":[1,2,4,{"bbb":"ttt"},432]}
        """
    val json = Json.parse(str)
    assert(json.asMap("asdf").asArray(0).asInt == 1)
    assert(json.asMap("asdf").asArray(3).asMap("bbb").asString == "ttt")
}
test("parse array") {
    val str =
        """
           [1,2,3,4,{"a":[1,2,3]}]
        """
    val json = Json.parse(str)
    assert(json.asArray(0).asInt == 1)
    assert(json(4)("a")(2).asInt == 3)
    assert(json(4)("a")(2).isInt)
    assert(json(4)("a").isArray)
    assert(json(4)("a").isMap == false)
}
test("real") {
    val str = "{\"styles\":[214776380871671808,214783111085424640,214851869216866304,214829406537908224],\"group\":100,\"name\":\"AO4614【金宏达电子】现货库存 质量保证 欢迎购买@\",\"shopgrade\":8,\"price\":0.59,\"shop_id\":60095469,\"C3\":50018869,\"C2\":50024099,\"C1\":50008090,\"imguri\":\"http://img.geilicdn.com/taobao10000177139_425x360.jpg\",\"cag\":50006523,\"soldout\":0,\"C4\":50006523}"
    val json = Json.parse(str)
    println(json.write())
    assert(json.asMap.size > 0)
}

Solution 12 - Json

I use uPickle which has the big advantage that it will handle nested case classes automatically:

object SerializingApp extends App {

  case class Person(name: String, address: Address)

  case class Address(street: String, town: String, zipCode: String)

  import upickle.default._

  val john = Person("John Doe", Address("Elm Street 1", "Springfield", "ABC123"))

  val johnAsJson = write(john)
  // Prints {"name":"John Doe","address":{"street":"Elm Street 1","town":"Springfield","zipCode":"ABC123"}}
  Console.println(johnAsJson)

  // Parse the JSON back into a Scala object
  Console.println(read[Person](johnAsJson))  
}

Add this to your build.sbt to use uPickle:

libraryDependencies += "com.lihaoyi" %% "upickle" % "0.4.3"

Solution 13 - Json

I use PLAY JSON library you can find the mavn repo for only the JSON library not the whole framework here

    val json = "com.typesafe.play" %% "play-json" % version
    val typesafe = "typesafe.com" at "http://repo.typesafe.com/typesafe/releases/"

A very good tutorials about how to use them, are available here:

http://mandubian.com/2012/09/08/unveiling-play-2-dot-1-json-api-part1-jspath-reads-combinators/

http://mandubian.com/2012/10/01/unveiling-play-2-dot-1-json-api-part2-writes-format-combinators/

http://mandubian.com/2012/10/29/unveiling-play-2-dot-1-json-api-part3-json-transformers/

Solution 14 - Json

Let me also give you the SON of JSON version:

import nl.typeset.sonofjson._

arr(
  obj(id = 1, name = "John)
  obj(id = 2, name = "Dani)
)

Solution 15 - Json

Play released its module for dealing with JSON independently from Play Framework, Play WS

Made a blog post about that, check it out at http://pedrorijo.com/blog/scala-json/

Using case classes, and Play WS (already included in Play Framework) you case convert between json and case classes with a simple one-liner implicit

case class User(username: String, friends: Int, enemies: Int, isAlive: Boolean)

object User {
  implicit val userJsonFormat = Json.format[User]
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid PortabellaView Question on Stackoverflow
Solution 1 - JsonAlex DeanView Answer on Stackoverflow
Solution 2 - JsonfmpwizardView Answer on Stackoverflow
Solution 3 - JsonparadigmaticView Answer on Stackoverflow
Solution 4 - JsonRamonView Answer on Stackoverflow
Solution 5 - JsonAlex PovarView Answer on Stackoverflow
Solution 6 - JsoneugenView Answer on Stackoverflow
Solution 7 - JsonAkavallView Answer on Stackoverflow
Solution 8 - JsonHRJView Answer on Stackoverflow
Solution 9 - JsonPiohenView Answer on Stackoverflow
Solution 10 - JsonBjornView Answer on Stackoverflow
Solution 11 - JsonmomodiView Answer on Stackoverflow
Solution 12 - JsonMatthias BraunView Answer on Stackoverflow
Solution 13 - JsonMontaroView Answer on Stackoverflow
Solution 14 - JsonWilfred SpringerView Answer on Stackoverflow
Solution 15 - Jsonpedrorijo91View Answer on Stackoverflow