Convert scala list to Json object - json

I want to convert a scala list of strings, List[String], to an Json object.
For each string in my list I want to add it to my Json object.
So that it would look like something like this:
{
"names":[
{
"Bob",
"Andrea",
"Mike",
"Lisa"
}
]
}
How do I create an json object looking like this, from my list of strings?

To directly answer your question, a very simplistic and hacky way to do it:
val start = """"{"names":[{"""
val end = """}]}"""
val json = mylist.mkString(start, ",", end)
However, what you almost certainly want to do is pick one of the many JSON libraries out there: play-json gets some good comments, as does lift-json. At the worst, you could just grab a simple JSON library for Java and use that.

Since I'm familiar with lift-json, I'll show you how to do it with that library.
import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonAST._
import net.liftweb.json.Printer._
import net.liftweb.json.JObject
val json: JObject = "names" -> List("Bob", "Andrea", "Mike", "Lisa")
println(json)
println(pretty(render(json)))
The names -> List(...) expression is implicitly converted by the JsonDSL, since I specified that I wanted it to result in a JObject, so now json is the in-memory model of the json data you wanted.
pretty comes from the Printer object, and render comes from the JsonAST object. Combined, they create a String representation of your data, which looks like
{
"names":["Bob","Andrea","Mike","Lisa"]
}
Be sure to check out the lift documentation, where you'll likely find answers to any further questions about lift's json support.

Related

Not able to convert Scala object to JSON String

I am using Play Framework and I am trying to convert a Scala object to a JSON string.
Here is my code where I get my object:
val profile: Future[List[Profile]] = profiledao.getprofile(profileId);
The object is now in the profile value.
Now I want to convert that profile object which is a Future[List[Profile]] to JSON data and then convert that data into a JSON string then write into a file.
Here is the code that I wrote so far:
val jsondata = Json.toJson(profile)
Jackson.toJsonString(jsondata)
This is how I am trying to convert into JSON data but it is giving me the following output:
{"empty":false,"traversableAgain":true}
I am using the Jackson library to do the conversion.
Can someone help me with this ?
Why bother with Jackson? If you're using Play, you have play-json available to you, which uses Jackson under the hood FWIW:
First, you need an implicit Reads to let play-json know how to serialize Profile. If Profile is a case class, you can do this:
import play.api.libs.json._
implicit val profileFormat = Json.format[Profile]
If not, define your own Reads like this.
Then since getprofile (which should follow convention and be getProfile) returns Future[List[Profile]], you can do this to get a JsValue:
val profilesJson = profiledao.getprofile(profileId).map(toJson)
(profiledao should also be profileDao.)
In the end, you can wrap this in a Result like Ok and return that from your controller.

Parsing the JSON representation of database rows in Scala.js

I am trying out scala.js, and would like to use simple extracted row data in json format from my Postgres database.
Here is an contrived example of the type of json I would like to parse into some strongly typed scala collection, features to note are that there are n rows, various column types including an array just to cover likely real life scenarios, don't worry about the SQL which creates an inline table to extract the JSON from, I've included it for completeness, its the parsing of the JSON in scala.js that is causing me problems
with inline_t as (
select * from (values('One',1,True,ARRAY[1],1.0),
('Six',6,False,ARRAY[1,2,3,6],2.4494),
('Eight',8,False,ARRAY[1,2,4,8],2.8284)) as v (as_str,as_int,is_odd,factors,sroot))
select json_agg(t) from inline_t t;
[{"as_str":"One","as_int":1,"is_odd":true,"factors":[1],"sroot":1.0},
{"as_str":"Six","as_int":6,"is_odd":false,"factors":[1,2,3,6],"sroot":2.4494},
{"as_str":"Eight","as_int":8,"is_odd":false,"factors":[1,2,4,8],"sroot":2.8284}]
I think this should be fairly easy using something like upickle or prickle as hinted at here: How to parse a json string to a case class in scaja.js and vice versa but I haven't been able to find a code example, and I'm not up to speed enough with Scala or Scala.js to work it out myself. I'd be very grateful if someone could post some working code to show how to achieve the above
EDIT
This is the sort of thing I've tried, but I'm not getting very far
val jsparsed = scala.scalajs.js.JSON.parse(jsonStr3)
val jsp1 = jsparsed.selectDynamic("1")
val items = jsp1.map{ (item: js.Dynamic) =>
(item.as_str, item.as_int, item.is_odd, item.factors, item.sroot)
.asInstanceOf[js.Array[(String, Int, Boolean, Array[Int], Double)]].toSeq
}
println(items._1)
So you are in a situation where you actually want to manipulate JSON values. Since you're not serializing/deserializing Scala values from end-to-end, serialization libraries like uPickle or Prickle will not be very helpful to you.
You could have a look at a cross-platform JSON manipulation library, such as circe. That would give you the advantage that you wouldn't have to "deal with JavaScript data structures" at all. Instead, the library would parse your JSON and expose it as a Scala data structure. This is probably the best option if you want your code to also cross-compile.
If you're only writing Scala.js code, and you want a more lightweight version (no dependency), I recommend declaring types for your JSON "schema", then use those types to perform the conversion in a safer way:
import scala.scalajs.js
import scala.scalajs.js.annotation._
// type of {"as_str":"Six","as_int":6,"is_odd":false,"factors":[1,2,3,6],"sroot":2.4494}
#ScalaJSDefined
trait Row extends js.Object {
val as_str: String
val as_int: Int
val is_odd: Boolean
val factors: js.Array[Int]
val sroot: Double
}
type Rows = js.Array[Row]
val rows = js.JSON.parse(jsonStr3).asInstanceOf[Rows]
val items = (for (row <- rows) yield {
import row._
(as_str, as_int, is_odd, factors.toArray, sroot)
}).toSeq

How to create a JSON object in Scala?

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.

How can I convert a json string to a scala map?

I have a nested json whose structure is not defined. It can be different each time I run since I am reading from a remote file. I need to convert this json into a map of type Map[String, Any]. I tried to look into json4s and jackson parsers but they don't seem to solve this issue I have.
Does anyone know how I can achieve this?
Example string:
{"body":{
"method":"string",
"events":"string",
"clients":"string",
"parameter":"string",
"channel":"string",
"metadata":{
"meta1":"string",
"meta2":"string",
"meta3":"string"
}
},
"timestamp":"string"}
The level of nesting can be arbitrary and not predefined.
To help with the use case:
I have a Map[String,Any] which I need to store in a file as backup. So I convert it to a json string and store it in a file. Now everytime I get new data, I need to get the json from the file, convert it to a map again and perform some computation. I cannot store the map in memory since I would lose that if my job fails.
I need a solution that would convert the json string back to the original map I had before i converted it.
I tried the following method with json4s 3.2.11 and it works:
import org.json4s._
import org.json4s.jackson.JsonMethods._
//...
def jsonStrToMap(jsonStr: String): Map[String, Any] = {
implicit val formats = org.json4s.DefaultFormats
parse(jsonStr).extract[Map[String, Any]]
}
Maybe you didn't define the implicit val of type Formats? Note also that you don't need to have an implicit val within every and each method as long as it's findable in the scope.
You can use the following code to parse a JSON string into a Map[String, Any]
import org.json4s._
import org.json4s.jackson.JsonMethods._
val jsonMap = parse(jsonString).values.asInstanceOf[Map[String, Any]]
However, this is not typesafe and hence should be used with caution when extracting values from the map.

Scala Convert a string into a map

What is the fastest way to convert this
{"a":"ab","b":"cd","c":"cd","d":"de","e":"ef","f":"fg"}
into mutable map in scala ? I read this input string from ~500MB file. That is the reason I'm concerned about speed.
If your JSON is as simple as in your example, i.e. a sequence of key/value pairs, where each value is a string. You can do in plain Scala :
myString.substring(1, myString.length - 1)
.split(",")
.map(_.split(":"))
.map { case Array(k, v) => (k.substring(1, k.length-1), v.substring(1, v.length-1))}
.toMap
That looks like a JSON file, as Andrey says. You should consider this answer. It gives some example Scala code. Also, this answer gives some different JSON libraries and their relative merits.
The fastest way to read tree data structures in XML or JSON is by applying streaming API: Jackson Streaming API To Read And Write JSON.
Streaming would split your input into tokens like 'beginning of an object' or 'beginning of an array' and you would need to build a parser for these token, which in some cases is not a trivial task.
Keeping it simple. If reading a json string from file and converting to scala map
import spray.json._
import DefaultJsonProtocol._
val jsonStr = Source.fromFile(jsonFilePath).mkString
val jsonDoc=jsonStr.parseJson
val map_doc=jsonDoc.convertTo[Map[String, JsValue]]
// Get a Map key value
val key_value=map_doc.get("key").get.convertTo[String]
// If nested json, re-map it.
val key_map=map_doc.get("nested_key").get.convertTo[Map[String, JsValue]]
println("Nested Value " + key_map.get("key").get)