1
votes

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)

1
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
If you want to use Jackson, take a look at the solutions offered at stackoverflow.com/a/6349488/14955 . Using Array[Data] looks simple and efficient. (unlike lists, arrays do know their runtime component type).Thilo

1 Answers

1
votes

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)