18

I have a Map like below

val map : scala.collection.mutable.Map[String,Any] = Map(
  dummy1 -> ["cat1", "hash1", 101, 1373269076, {"1" : ["dummy", "dummy", "dummy"]}],
  dummy2 -> ["cat1", "hash1", 102, 1373269076, {"2" : ["dummy", "dummy", "dummy"]}],
  dummy3 -> ["cat1", "hash1", 103, 1373269076, {"3" : ["dummy", "dummy", "dummy"]}]
)

I converted it into a Json string and then wrote it into a file with the code below

Some(new PrintWriter("foo.txt")).foreach{p =>
  p.write(JSONObject(map.toMap).toString()); p.close
}

Am able to read the Json string from the file using

val json_string = scala.io.Source.fromFile("foo.txt").getLines.mkString

How do I get my map back from the Json string above?

EDIT: Am able to read the map with

val map1 = JSON.parseFull(json_string).get.asInstanceOf[Map[String,Any]]

But, this process is taking more time as the size of the map increases.

yAsH
  • 3,367
  • 8
  • 36
  • 67
  • 1
    By `more time`, do you mean O(n) or something worse? If worse, consider expanding your heap. – Ed Staub Nov 12 '13 at 21:22
  • The [ujson](https://github.com/lihaoyi/upickle) library is the best modern solution. The library in the accepted answer has been archived and isn't active anymore. See my answer for more details. – Powers Dec 17 '20 at 18:41

3 Answers3

13

Try using a likely faster (and more thorough) mapper.

I would recommend using JacksMapper which wraps the excellent Jackson for a more pleasant Scala usage.

Serializing to JSON becomes as simple as

val json = JacksMapper.writeValueAsString[MyClass](instance)

... and deserializing

val obj = JacksMapper.readValue[MyClass](json)

(edit)

You can make also writing and reading simple one-liners using FileUtils from commons-io doing

val json = FileUtils readFileToString (file, encoding)

and

FileUtils write (file, json, encoding) 
Bruno Grieder
  • 28,128
  • 8
  • 69
  • 101
  • which Scala version does it support? – yAsH Jul 08 '13 at 12:52
  • From the first page `This version of jacks has been tested against Scala 2.9.3, 2.10.2 and Jackson 2.2.2` – Bruno Grieder Jul 08 '13 at 13:15
  • Am using Scala 2.9.3-RC2. Am getting the error jacks_2.10-2.2.2.jar is cross-compiled with an incompatible version of Scala (2.10) immediately after adding the jar file to the project. – yAsH Jul 08 '13 at 13:31
  • I am using it with 2.10.2. Did you get the correct one ? Accoridng to my maven repo the 2.9.3 version is ` com.lambdaworks jacks_2.9.3 2.2.0 ` – Bruno Grieder Jul 08 '13 at 13:40
  • I did the same. There are no errors in the code. But, eclipse is showing 2 problems 1) Error in Scala compiler, 2) SBT builder crashed while compiling. Do I need to add Jackson jar too? – yAsH Jul 09 '13 at 04:36
  • yes. This is just a wrapper around Jackson. Jackson-databind 2.2.2 should do. – Bruno Grieder Jul 09 '13 at 05:26
  • to be thorough (in case you do not use Maven and pull dependencies automagically), you need jackson-core, jackson-databind and jackson-annotations – Bruno Grieder Jul 09 '13 at 13:23
5

I actually got a lot more use from json4s. The documentation is much more clear and comprehensive, and the usage seems slightly easier.

A similar operation to the one you are requesting would look like this

import org.json4s.native.JsonFormats.parse

... get your json string ...
val parsedJson = parse(json)
val extractedJson = parsedJson.extract[MyClass]
Greg
  • 5,422
  • 1
  • 27
  • 32
3

ujson is the best modern solution to read and write JSON.

Here's how to build up an object and write it to disk:

val weirdData = ujson.Obj(
  "something1" -> ujson.Arr("cat1", "hash1", 101),
  "something2" -> ujson.Arr("cat2", "hash2", 102),
  "something3" -> ujson.Arr("cat3", "hash3", 103)
)
os.write(os.pwd/"tmp"/"weird_data.json", weirdData)

Here are the contents of the weird_data.json file:

{
  "something1":["cat1","hash1",101],
  "something2":["cat2","hash2",102],
  "something3":["cat3","hash3",103]
}

You can easily read this data from a JSON file to a ujson object.

val jsonString = os.read(os.pwd/"tmp"/"weird_data.json")
val data = ujson.read(jsonString)
// here's what data contains
ujson.Value.Value = Obj(
  LinkedHashMap(
    "something1" -> Arr(ArrayBuffer(Str("cat1"), Str("hash1"), Num(101.0))),
    "something2" -> Arr(ArrayBuffer(Str("cat2"), Str("hash2"), Num(102.0))),
    "something3" -> Arr(ArrayBuffer(Str("cat3"), Str("hash3"), Num(103.0)))
  )
)

Here's how to grab a value from the ujson object.

data("something2")(1).str // "hash2"

See here for more details on writing JSON data with Scala.

Powers
  • 18,150
  • 10
  • 103
  • 108