Given the following object
object functions {
type MyOutput = String
def f1: MyOutput = "res1"
def f2: MyOutput = "res2"
def f3(foo: String): Boolean = foo.equals("bar")
def f4(in:String): MyOutput = in "res4"
}
Is it possible to call all methods on this object, which the returned type is of MyOutput type?
Currenly I tried to use reflection for this, but had no luck with it.
import scala.reflect.runtime.universe._
val m = runtimeMirror(getClass.getClassLoader)
val instanceMirror = m.reflect(typeOf[functions.type])
val classSymbol = m.classSymbol(functions.getClass)
val methods = classSymbol.info.members.filter(_.isMethod)
methods.foreach({
method =>
if (method.info.resultType.toString.contains("MyOutput")) {
println(method.name.toString)
val methodm = instanceMirror.reflectMethod(method.asMethod)
methodm()
}
})
This is the error
scala.ScalaReflectionException: expected a member of class UniqueSingleType, you provided method
CodePudding user response:
val instanceMirror = m.reflect(functions)
should be instead of
val instanceMirror = m.reflect(typeOf[functions.type])
This was the mistake because it's functions that is an instance, not typeOf[functions.type] (which is UniqueSingleType as written in the error).
Also there can be some improvements.
val classSymbol = m.classSymbol(functions.getClass)
val methods = classSymbol.info.members.filter(_.isMethod)
can be now replaced with
val methods = typeOf[functions.type].decls.toList.filter(_.isMethod)
since you know the object functions at compile time (so you don't need .classSymbol) and you're interested in the object methods rather than methods of its parents (so this is .decls rather than .members).
It's better to replace
method.info.resultType.toString.contains("MyOutput")
with
method.info.resultType =:= typeOf[String]
(aka method.info.resultType =:= typeOf[functions.MyOutput]) in order not to rely on a work with raw strings.
In methodm() you should provide arguments for the method:
methodm(...here...)
