Home > Software engineering >  Invoke all methods on a Scala object using reflection
Invoke all methods on a Scala object using reflection

Time:02-04

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...)
  • Related