2

I am writing a small scala practice code where my input is going to be in the fashion -

{
  "code": "",
  "unique ID": "",
  "count": "",
  "names": [
    {
      "Matt": {
        "name": "Matt",
        "properties": [
          "a",
          "b",
          "c"
        ],
        "fav-colour": "red"
      },
      "jack": {
        "name": "jack",
        "properties": [
          "a",
          "b"
        ],
        "fav-colour": "blue"
      }
    }
  ]
}

I'll be passing this file as an command line argument. I want to know that how do I accept the input file parse the json and use the json keys in my code?

1
  • 1
    Maybe check any of scala json parsing libraries? My recommendation is circe. Commented Jan 12, 2019 at 8:56

1 Answer 1

3

You may use a json library such as play-json to parse the json content.

You could either operate on the json AST or you could write case classes that have the same structure as your json file and let them be parsed.

You can find the documentation of the library here.


You'll first have to add playjson as depedency to your project. If you're using sbt, just add to your build.sbt file:

libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.13"

Play json using AST

Let's read the input file:

import play.api.libs.json.Json

object Main extends App {
  // first we'll need a inputstream of your json object
  // this should be familiar if you know java.
  val in = new FileInputStream(args(0))

  // now we'll let play-json parse it
  val json = Json.parse(in)
}

Let's extract some fields from the AST:

val code = (json \ "code").as[String]
val uniqueID = (json \ "unique ID").as[UUID]

for {
  JsObject(nameMap) ← (json \ "names").as[Seq[JsObject]]
  (name, userMeta) ← nameMap // nameMap is a Map[String, JsValue]
} println(s"User $name has the favorite color ${(userMeta \ "fav-colour").as[String]}")

Using Deserialization

As I've just described, we may create case classes that represent your structure:

case class InputFile(code: String, `unique ID`: UUID, count: String, names: Seq[Map[String, UserData]])

case class UserData(name: String, properties: Seq[String], `fav-colour`: String)

In addition you'll need to define an implicit Format e.g. in the companion object of each case class. Instead of writing it by hand you can use the Json.format macro that derives it for you:

object UserData {
  implicit val format: OFormat[UserData] = Json.format[UserData]
}

object InputFile {
  implicit val format: OFormat[InputFile] = Json.format[InputFile]
}

You can now deserialize your json object:

val argumentData = json.as[InputFile]

I generally prefer this approach but in your case the json structure does not fit really well. One improvement could be to add an additional getter to your InputFile class that makes accesing the fields with space and similar in the name easier:

case class InputFile(code: String, `unique ID`: UUID, count: String, names: Seq[Map[String, String]]) {
  // this method is nicer to use
  def uniqueId = `unique ID`
}
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, Thank you so much. I have successfully implemented the same and it works! However, I'm not able to access the elements inside 'names'. How do I declare them ? so that I can iterate on those elements and perform some operations.
If you're accessing the names array via the ast, you have a list of json values, that you may e.g. iterate through or use the map function to extract data from each element within the list. I've added an example for your case. Did you define the structure of the json object? If so, I'd rethink it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.