1

My JSON File containes below details { "category":"age, gender,post_code" }

My scala code is below one

val filename = args.head
println(s"Reading ${args.head} ...")
val json = Source.fromFile(filename)
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
val parsedJson = mapper.readValue[Map[String, Any]](json.reader())   
val data = parsedJson.get("category").toSeq

It's returning Seq(Any) = example List(age, gender,post_code) but I need Seq(String) output please if any has an idea about this please help me.

prayagupa
  • 30,204
  • 14
  • 155
  • 192
JSF Learner
  • 183
  • 2
  • 7
  • 15

3 Answers3

1

The idea in scala is to be typesafe whenever possible which you are giving away using Map[String, Any].

So, I recommend using a data class that represents your JSON data.

Example,

define a mapper,

scala> import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper

scala> import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

scala> import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.DefaultScalaModule

scala> val mapper = new ObjectMapper() with ScalaObjectMapper
mapper: com.fasterxml.jackson.databind.ObjectMapper with com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper = $anon$1@d486a4d

scala> mapper.registerModule(DefaultScalaModule)
res0: com.fasterxml.jackson.databind.ObjectMapper = $anon$1@d486a4d

Now, when you deserialise to Map[K, V] you can not specify all the nested data-structures,

scala> val jsonString = """{"category": ["metal", "metalcore"], "age": 10, "gender": "M", "postCode": "98109"}"""
jsonString: String = {"category": ["metal", "metalcore"], "age": 10, "gender": "M", "postCode": "98109"}

scala> mapper.readValue[Map[String, Any]](jsonString)
res2: Map[String,Any] = Map(category -> List(metal, metalcore), age -> 10, gender -> M, postCode -> 98109)

Following is a solution casting some key to desired data-structure but I personally don not recommend.

scala> mapper.readValue[Map[String, Any]](jsonString).get("category").map(_.asInstanceOf[List[String]]).getOrElse(List.empty[String])
res3: List[String] = List(metal, metalcore)

Best solution is to define a data class which I'm calling SomeData in following example and deserialize to it. SomeData is defined based on your JSON data-structure.

scala> final case class SomeData(category: List[String], age: Int, gender: String, postCode: String)
defined class SomeData

scala> mapper.readValue[SomeData](jsonString)
res4: SomeData = SomeData(List(metal, metalcore),10,M,98109)

scala> mapper.readValue[SomeData](jsonString).category
res5: List[String] = List(metal, metalcore)
prayagupa
  • 30,204
  • 14
  • 155
  • 192
  • Thanks for your suggestion, however, in my case I don't have predefined JSON for case class it will always keep on change. It would be dynamic values – JSF Learner Jul 02 '18 at 07:15
  • There are ways for that too. Spend some time learning types in scala. Otherwise you can use `_.asInstanceOf` as in updated answer => `.get("category").map(_.asInstanceOf[List[String]]).getOrElse(List.empty[String])` which I dont recommend. – prayagupa Jul 02 '18 at 07:24
  • the above one is perfectly working for me, do you any reason for not recommend, if I use what would be the problem? – JSF Learner Jul 02 '18 at 08:21
0

Just read the JSON as a JsonNode, and access the property directly:

val jsonNode = objectMapper.readTree(json.reader())
val parsedJson = jsonNode.get("category").asText
cbley
  • 4,538
  • 1
  • 17
  • 32
0
  • By using the scala generic function for converting the JSON String to Case Class/Object you can de-serialize to anything you want. Like

    • JSON to Collection,
    • JSON to Case Class, and
    • JSON to Case Class with Object as field.
  • Please find a working and detailed answer which I have provided using generics here.

Keshav Lodhi
  • 2,641
  • 2
  • 17
  • 23