简体   繁体   中英

How to compare the return type of a method to a Scala native or TypeTag?

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

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" .)

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'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM