Reputation: 902
So, I'm using the Scala reflections library, and I'm trying to check if a method conforms to a given type. To simplify, I'm trying to check only its output.
What I have now is:
val returnType = methodSymbol.returnType
// returnType: reflect.runtime.universe.Type = java.lang.String
So, I can read it is a String, but it has this terrible type reflect.runtime.universe.Type
. How on Earth can I compare check if this return type is a simple String? I even tried using TypeTags, which are simple enough, but to convert a Type
to a TypeTag
is such a monumental effort that I fail to believe such a simple task cannot be achieved with more simply.
So, how can I compare this to a String and simply get a boolean back?
I thought of simply calling a toString()
and trying to parse that back to a normal type, but that would be really disgusting to do on the code, IMO. Also, I cannot simply specify the method name, because I'm working on a list of methods, and more will come later.
I've seen some questions, and even this (in my opinion, absurdly complex) answer on how to convert a Type to a TypeTag, but, again, I'm baffled by the level of complexity for such a trivial task. I'm already thinking of pulling my scarce hair out. Help appreciated.
EDIT: I've managed to make the comparison for the String itself, but not for a method returning the String.
To compare the String return type, I'm doing:
val returnType = methodSymbol.returnType
returnType =:= typeTag[String].tpe
When I try to check it with inheritance and a method, though, using <:<
, it won't work. To clarify, B extends Trait A, the type signature is () => B
, but I cannot match when coding
val typeSig = methodSymbol.typeSig
typeSig <:< typeTag[() => A].tpe
Upvotes: 2
Views: 279
Reputation: 51683
If you want to work with types as String
s you should parse them
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val str = "java.lang.String"
val tpe: Type = (tb.typecheck(tb.parse(s"type T = $str"), mode = tb.TYPEmode) match {
case q"type T = $typ" => typ
}).tpe // String
tpe =:= typeOf[String] //true
(I would like to do just tb.typecheck(tb.parse(str/*, mode = ???*/), mode = tb.TYPEmode).tpe
but can't find how to call TypeParser
instead of TermParser
with runtime reflection, this corresponds to difference between tq"..."
and q"..."
, otherwise I get String
companion instead of String
itself. Surely tq"$str"
gives wrong type too because it's a macro, it can work only for compile-time literals: tq"java.lang.String"
.)
Upvotes: 5
Reputation: 2821
Maybe not exactly what you're asking for, but you can use java.lang.reflect
in Scala.
import java.lang.reflect.Method
class C {
def doSomething(): String = {
return "hello"
}
def doSomethingElse(): String = {
return "bye"
}
def doNothing(): Int = {
return 190
}
}
val doSomethingMethod: Method = classOf[C].getMethods()(2)
val doNothingMethod: Method = classOf[C].getMethods()(1)
val doSomethingElseMethod: Method = classOf[C].getMethods()(0)
// false
doSomethingMethod.getReturnType.equals(doNothingMethod.getReturnType)
// true
doSomethingMethod.getReturnType.equals(doSomethingMethod.getReturnType)
// you can compare the simple name, too, if that's easier
println(s"'${doSomethingMethod.getReturnType.getSimpleName}'")
// 'String'
Upvotes: 5