Search code examples
scalareflectionshapeless

Type casting using type parameter


Given is a Java method that returns java.lang.Objects for a given string. I'd like to wrap this method in a Scala method that converts the returned instances to some type T. If the conversion fails, the method should return None. I am looking for something similar to this:

def convert[T](key: String): Option[T] = {
  val obj = someJavaMethod(key)
  // return Some(obj) if obj is of type T, otherwise None
}

convert[Int]("keyToSomeInt") // yields Some(1)
convert[String]("keyToSomeInt") // yields None

(How) Can this be achieved using Scala's reflection API? I am well aware that the signature of convert might have to be altered.


Solution

  • That's what a ClassTag is for:

    import reflect.ClassTag
    
    def convert[T : ClassTag](key: String): Option[T] = {
      val ct = implicitly[ClassTag[T]]
      someJavaMethod(key) match {
        case ct(x) => Some(x)
        case _ => None
      }
    }
    

    It can be used as an extractor to test and cast to the proper type at the same time.

    Example:

    scala> def someJavaMethod(s: String): AnyRef = "e"
    someJavaMethod: (s: String)AnyRef
    
    [...]
    
    scala> convert[Int]("key")
    res4: Option[Int] = None
    
    scala> convert[String]("key")
    res5: Option[String] = Some(e)
    

    Edit: Note however that a ClassTag does not automatically unbox boxed primitives. So, for example, convert[Int]("a") would never work, because the java method returns AnyRef, it would have to be convert[java.lang.Integer]("a"), and so on for other primitive types.

    Miles's answer with Typeable seems to take care of those edge cases automatically.