First, I searched a lot on Google and StackOverflow for questions like that, but I didn't find any useful answers (to my big surprise).
I saw something about Play Framework, how to create JSON array in Java and how to create JSON objects in Java, but I don't want to use Play Framework and I don't know if the creation of JSON objects differ from Scala to Java.
Following is the JSON I want to create. Later I'll convert the object into a string to send it via a POST request (through an API call).
{
"start_relative": {
"value": "5",
"unit": "years"
},
"metrics": [
{
"name": "DP_391366" # S-Temperature - Celsius
},
{
"name": "DP_812682" # Sensor-A4 Luminosity
}
]
}
How can I do something like that in Scala?
You should use a library that handles serialization/deserialization.
I would consider choosing between Spray Json and Play Json.
I will explain to you how the process works with Play first, and it's very similar to that in Spray.
Let's say you have a class, and an object with an instance and a json as string:
case class MyClass(id: Int,
name: String,
description: String)
object Data {
val obj: MyClass = MyClass(1, "me", "awesome")
val str: String =
"""
|{
| "id": 1,
| "name": "me",
| "description": "awesome"
|}
""".stripMargin
}
For MyClass to be serialized/deserialized, you will need an implicit formatter, specific for this, so you will create an object that contains this formatter using Play.
trait MyClassPlayProtocol {
implicit val formatAbility = Json.format[Ability]
}
object MyClassPlayProtocol extends MyClassPlayProtocol
The serialization/deserialization will look something like this:
object PlayData {
import play.api.libs.json.JsValue
import play.api.libs.json.Json
import MyClassPlayProtocol._
import General._
val str2Json: JsValue = Json.parse(str)
val obj2Json: JsValue = Json.toJson(obj)
val json2Str: String = Json.stringify(str2Json)
val json2Obj: MyClass = obj2Json.as[MyClass]
}
In Spray, the protocol will look like this:
trait MyClassSprayProtocol extends DefaultJsonProtocol {
implicit val myClassFormat = jsonFormat3(MyClass)
}
object MyClassSprayProtocol extends MyClassSprayProtocol
and the serialization/deserialization:
object SprayData {
import spray.json._
import MyClassSprayProtocol._
import General._
val str2Json: JsValue = str.parseJson
val obj2Json: JsValue = obj.toJson
val json2Str: String = str2Json.compactPrint
val json2Obj: MyClass = obj2Json.convertTo[MyClass]
}
As you can see, it's mostly a matter of choice between this two. Both are still improved and probably will be in the near future.
Depending on the benchmark, you will find that one is better than the other by a few miliseconds (usually Spray).
I for one am using Spray at work and Play in some personal projects, and I can't say I found something fundamentally different from one to another.
EDIT:
And to finally answer your question, to go from MyClass to String (serialization), you will do something like this:
PLAY: Json.stringify(Json.toJson(myClass))
SPRAY: myClass.toJson.compactPrint
And the deserialization:
PLAY: Json.parse(string).as[MyClass]
SPRAY: myClass.parseJson.convertTo[MyClass]
You need to use a library if you dont want it to do by yourself there are serveral:
Spray Json - https://github.com/spray/spray-json
Lift Json - https://github.com/lift/lift/tree/master/framework/lift-base/lift-json/
Jerkson - https://github.com/codahale/jerkson
Jackson - You can use Jackson with the scala Module https://github.com/FasterXML/jackson-module-scala
Note: The cool Java Gson LIbrary looses a lot of Magic if you want to use it with Scala, because they dont know Collections. So if you want to use this library you have to convert the "Scala List" to java.util.List and after that use Gson.
I'm using playframework 2.1.0 with Anorm to query a db.
I want to serialize the result to json without going through any interim objects/case classes.
this is what the flow looks like:
Using anorm:
DB.withConnection { implicit c =>
val q = SQL(""" long query goes here """)
q().toList
}
then I take this result and transform it from a List[SqlRow] to List[Map[String,Any]].
String,Any is the column name, value (Object/Any)
val asMap = info.toList.map(row => scala.collection.immutable.Map(row.asMap.toSeq:_*))
The i'd like to jsonize this.
I tried some json libs : GSON, spray-json, playframework json lib.
But none of them seem to work with Any out of the box.
I tried writing implicit writer for the Any type with some pattern matching, but the problem is that this writer always overtakes all the other writes so the json is not produced correctly.
Advise?
How would you suggest transforming a result from Anorm to Json? without any interim domain models.
found a solution, not the best, using FlexJson.
The annoying thing is that FlexJson is not very scala oriented so scala collections and some scala types need to be converted to the equivalent Java type.
val info:List[SqlRow] = loadInfoFromDB using Anorm
//transform scala maps to java maps
val asMap: List[util.Map[String, Any]] = info.toList.map(row => JavaConversions.mapAsJavaMap(row.asMap))
//create the basic FlexJson serializer
val flexJson: JSONSerializer = new flexjson.JSONSerializer()
//register a Option transformer so it can serialize Options correctly
flexJson.transform(new flexjson.transformer.AbstractTransformer {
def transform(`object`: Any) {
`object`.asInstanceOf[Option[_]] match {
case None => getContext.write("null")
case Some(b:Any) => getContext.transform(b)
}
}
},classOf[Option[_]])
//finally convert the scala List to java List and use this serializer on it.
val infoJsn: String = flexJson.deepSerialize(JavaConversions.seqAsJavaList(asMap))
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
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?
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:
parsing.json.JSON - Warning this library is available only up to Scala version 2.9.x (removed in newer versions)
spray-json - Extracted from the Spray project
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
sjson - By Debasish Ghosh
lift-json - Can be used separately from the Lift project
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
Argonaut 💣
§ - A FP-oriented JSON library for Scala, from the people behind Scalaz
play-json ± - Now available standalone, see this answer for details
dijon - A handy, safe and efficient JSON library, uses jsoniter-scala under hood.
sonofjson - JSON library aiming for a super-simple API
Jawn - JSON library by Erik Osheim aiming for Jackson-or-faster speed
Rapture JSON ± - a JSON front-end which can use 2, 4, 5, 6, 7, 11 or Jackson as back-ends
circe 💣 - fork of Argonaut built on top of cats instead of scalaz
jsoniter-scala - Scala macros for compile-time generation of ultra-fast JSON codecs
jackson-module-scala - Add-on module for Jackson to support Scala-specific datatypes
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.
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.
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"}]
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
}
}
}
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.
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 :)
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)
}
}
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.
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
#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.
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)
}
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"
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/
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)
)
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]
}
Given, for example, the following JSON string:
[{"id": "user1", "password": "ps1"},{"id": "user2", "password": "ps2"},{"id": "user3", "password": "ps3"}]
What's the best and most optimized way to parse it in Scala and iterate through every result and analise it properly?
Thank you.
with Lift-JSON:
import net.liftweb.json.JsonParser._
import net.liftweb.json.DefaultFormats
val jsonString = //your jsonString....
case class Credential (id:String, password:String)
implicit val formats = DefaultFormats
val credentials = parse(jsonString).extract[List[Credential]]
credentials foreach { cred => println(cred.id + " " + cred.password) }
everything is explain here : http://www.assembla.com/spaces/liftweb/wiki/JSON_Support
I think this blogpost gives an comprehensive answer to your question: http://debasishg.blogspot.com/2011/02/applicatives-for-composable-json.html at the end there is also a link to a full source repository.
You could use lift-json library : http://www.assembla.com/spaces/liftweb/wiki/JSON_Support
Aside from lift-json, and the type class approach mentioned above, I know of spray-json (PEG parser), and twitter's json lib (based on the code in the Programming in Scala book) and the json lib in blueeyes. There are others!
I suggest taking a look at Jackson which is a mature and feature-rich library for JSON-parsing from Java.
Jackson has an "official" extension for scala: jackson-module-scala and another one Jerkson.
There's a JSON parsing library in the framework, built using the parser combinators: http://www.scala-lang.org/api/current/scala/util/parsing/json/package.html
Odersky and Venners walk you through it in their book, one of the last chapters.