1

Recently, I was trying to do a simple Scala code to analyse COVID - 19 data, I called one API and cast structure of that JSON API call to my Scala case classes. If I do not apply filters code is working as expected, When I try to apply filter it do not work, Little bit confused. Why it is not working.

case class RegionData(region: Option[String], totalInfected: Option[String], recovered: Option[String], deceased: Option[String])

case class Data(activeCases: String, recovered: String, deaths: String, totalCases: String, sourceUrl: String, lastUpdatedAtApify: String, readMe: String, regionData: Option[List[RegionData]])

These are my case classes for Scala.

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

import scala.io.Source

object CovidAnalytics {
  val objectMapper: ObjectMapper = new ObjectMapper()
  objectMapper.registerModule(DefaultScalaModule)

  def main(args: Array[String]): Unit = {
    val getData: String = Source.fromURL("https://api.apify.com/v2/datasets/58a4VXwBBF0HtxuQa/items?format=json&clean=1").mkString
    val data: List[Data] = objectMapper.readValue(getData, classOf[List[Data]])
    //This is working
    println(data)

    val filter = data.filter(e => e.deaths != "")
    //This is not working (Confused!!!)
    println(filter)
  }
}

Exception in thread "main" java.lang.ClassCastException: scala.collection.immutable.HashMap$HashTrieMap cannot be cast to com.example.analytics.Data at com.example.analytics.CovidAnalytics$$anonfun$1.apply(CovidAnalytics.scala:18) at scala.collection.TraversableLike$$anonfun$filterImpl$1.apply(TraversableLike.scala:248) at scala.collection.immutable.List.foreach(List.scala:392) at scala.collection.TraversableLike$class.filterImpl(TraversableLike.scala:247) at scala.collection.TraversableLike$class.filter(TraversableLike.scala:259) at scala.collection.AbstractTraversable.filter(Traversable.scala:104) at com.example.analytics.CovidAnalytics$.main(CovidAnalytics.scala:18) at com.example.analytics.CovidAnalytics.main(CovidAnalytics.scala)

Jayant Chauhan
  • 173
  • 1
  • 12
  • That does not work. Generic types in Java are erased at runtime, so `classOf[List[Data]]` is just `classOf[List[_]]` and Jackson has no way to know that you want to use your `Data` case-class. Easiest solution is to use a Scala JSON library (such as Circe, PlayJSON, or uPickle). – Thilo May 09 '20 at 14:02
  • If you want to use Jackson, take a look at the solutions offered at https://stackoverflow.com/a/6349488/14955 . Using `Array[Data]` looks simple and efficient. (unlike lists, arrays do know their runtime component type). – Thilo May 09 '20 at 14:05

1 Answers1

1

This is happening because of the type erasure. You can replace List by Array.

    val getData: String = Source.fromURL("https://api.apify.com/v2/datasets/58a4VXwBBF0HtxuQa/items?format=json&clean=1").mkString

    val data = objectMapper.readValue(getData, classOf[Array[Data]]).toList //.toList if you need it as List
    println(data)

    val filter = data.filter(e => e.deaths != "")
    println(filter)
Belwal
  • 453
  • 1
  • 4
  • 15