how can i pattern match on runtime class in scala

1.3k views Asked by At

I have a snippet of code like this:

override def getOption[T: TypeTag: ClassTag](path: String): Option[T] = {
  implicitly[scala.reflect.ClassTag[T]].toString() match {
    case "java.lang.String" => HandleBlank(super.getOption[String](path)).asInstanceOf[Option[T]]
    case _ => super.getOption[T](path)
  }
}

I assume there must be a better way to do this than matching by string, but tried a few things (like classOf[String]) and can't seem to find something that works.

For context, getOption (in the superclass that we are trying to override) gets an Option value from a json4s AST JValue object

def getOption[T: TypeTag: ClassTag](path: String): Option[T] = Try(getJValue(path).extract[T]).toOption

def getJValue(path: String): JValue = {
  path.split('.').foldLeft(value)((a, b) => a \ b) match {
    case JNull => JNothing
    case j     => j
  }
}

The idea is that I want to shim it so that for only String types of that method, we want to handle blank strings in a special way.

2

There are 2 answers

0
HTNW On BEST ANSWER

You can do direct equality tests between ClassTags like this:

override def getOption[T: TypeTag: ClassTag](path: String): Option[T] = {
  // not required, just nicer to write classTag[T] vs. implicitly[ClassTag[T]]
  import reflect.classTag
  classTag[T] match {
    case strTag if strTag == classTag[String] => HandleBlank(super.getOption[String](path)).asInstanceOf[Option[T]]
    case _ => super.getOption[T](path)
  }
}
0
Alexey Romanov On

One common trick is to put the value you want to compare with into a local variable or a field:

import scala.reflect.classTag

val StringTag = classTag[String]

override def getOption[T: TypeTag: ClassTag](path: String): Option[T] = {
  classTag[T] match {
    case StringTag => ...
    case _ => ...
  }
}

Note that the name should start with a capital letter, otherwise case stringTag will just bind a fresh variable (though you can surround stringTag with ` to fix this).