0

So I am trying to pattern match a List of a custom object which has been converted from Json. The compiler cannot determine the content of Sequences, e.g. List[Int] is the same as List[String] so I'm currently not able to differentiate between the different objects and therefore cannot handle them correctly.

I have retrieved Json data, transformed it and then successfully mapped it to my models so the myFunction (below) is the part which is causing the problem - in not being able to identify the data type:

  trait SuperT

  case class User(firstname: String, firstname: String, dob: Option[Date]) extends SuperT

  case class Country(name: String, continent: Option[String], hemisphere: Option[String]) extends SuperT

  def myFunction(jsRes: JsResult[Seq[SuperT]])(implicit request: Request[AnyContent]) = {

    jsRes match {
      case JsSuccess(data: List[SuperT], path: JsPath) => data match {
        // cannot find the differences between the following 2 case types
        case u: List[User] => Ok(views.html.db.user.index(Some(u))
        case c: List[RgnM] => Ok(views.html.db.country.index(Some(c))
      }
      case e: JsError => Ok(JsError.toJson(e))
    }

  }

Any help or insight is appreciated!

  • 1
    Possible duplicate of [How to pattern match on generic type in Scala?](https://stackoverflow.com/questions/16056645/how-to-pattern-match-on-generic-type-in-scala) – markusthoemmes Apr 20 '18 at 16:37
  • @markusthoemmes - it's similar but not the same and importantly the solution for that question doesn't seem helpful. Without complicating the issue; as each template specifies each `List Type` it must be passed on as that exact `List Type`. – jesus g_force Harris Apr 20 '18 at 16:41

1 Answers1

1

it's similar but not the same and importantly the solution for that question doesn't seem helpful

The problem is exactly the same as in the question @markusthoemmes linked. However, it may not be obvious which solutions are applicable and how they need to be adapted, especially without enough Scala experience.

If you just have a List[SuperT] obtained from somewhere, Manifest/ClassTag/TypeTag based solutions won't help. They require having a List[User] at some stage.

case JsSuccess(data: List[SuperT], path: JsPath) => data match {
  case first :: _ =>
    first match {
      case _: User => 
        Ok(views.html.db.user.index(Some(data.asInstanceOf[List[User]]))
      case _: Country =>
        Ok(views.html.db.country.index(Some(data.asInstanceOf[List[Country]]))
    }
  case _ => // what do you want to do if the list is empty (or null)?
}

should work if you can assume the list contains either only Users or only Countryes. Otherwise you can use partition or groupBy to split into lists by class and decide what to do with each.

But you should also consider why you have a List[SuperT] in the first place; at the moment you create it, don't you have information about whether users or countries will be contained in the response? If you do, it can be passed together with the list and solve your problem without type-matching ugliness.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Yes this does look like a messy way of doing it so I have found a easier solution as you suggested. I wish that there was a simple of pattern matching on `Monads` in general - I'm currently trying to do so with `scala forms` (to avoid unnecessary code for each model). – jesus g_force Harris Apr 24 '18 at 11:45