8

I have a class name and a method whose type parameters I know, and I'd like to invoke this method via reflection.

In java I'd do something like:

Class.forName("foo").getMethod("name", ... type args...).invoke(null, ..args)

However in Scala, whenever I try and invoke I get a null ref error.

I'm using scala 2.10.4

-- EDIT

I have tried:

$ scala
Welcome to Scala version 2.10.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class Foo { def bar(x: Int) = x }
defined class Foo

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> val foo = new Foo
foo: Foo = Foo@2db7a79b

scala> runtimeMirror(getClass.getClassLoader).reflect(foo)
res0: reflect.runtime.universe.InstanceMirror = instance mirror for Foo@2db7a79b

scala> res0.symbol.typeSignature.member(newTermName("bar"))
res1: reflect.runtime.universe.Symbol = method bar

scala> res0.reflectMethod(res1.asMethodSymbol)(42)
<console>:15: error: value asMethodSymbol is not a member of reflect.runtime.universe.Symbol
              res0.reflectMethod(res1.asMethodSymbol)(42)
                                      ^

As an example from "Dynamic" method invocation with new Scala reflection API which doesn't seem to work anymore

Here is a test of what I am trying to do:

object Test{
  def run(): Boolean = true
}

class InvokeTests extends FlatSpec with Matchers {
  "invoke" should "do" in {
    import scala.reflect.runtime.universe._

    val mirror = runtimeMirror(this.getClass.getClassLoader)

    val moduleSymbol = mirror.moduleSymbol(Class.forName(Test.getClass.getName))

    val reflected = mirror.reflect(moduleSymbol)

    val methodName = reflected.symbol.typeSignature.member(newTermName("run"))

    reflected.reflectMethod(methodName.asMethod)() shouldBe true
  }
}
Community
  • 1
  • 1
devshorts
  • 8,572
  • 4
  • 50
  • 73
  • This has an answer here: http://stackoverflow.com/questions/11062166/dynamic-method-invocation-with-new-scala-reflection-api In the answer there is a link to reach the companion object through reflection api also. – Samar Aug 25 '16 at 01:24
  • Hmm, @Samar that example doesn't seem to work (maybe there were changes since the scala version?) – devshorts Aug 25 '16 at 01:46
  • Please check the answer. Its working fine for Scala 2.11.8 – Samar Aug 25 '16 at 05:26

2 Answers2

5

Refer scala doc reflection overview

// get runtime universe
val ru = scala.reflect.runtime.universe

// get runtime mirror
val rm = ru.runtimeMirror(getClass.getClassLoader)

// define class and companion object
class Boo{def hey(x: Int) = x}; object Boo{def hi(x: Int) = x*x}

// get instance mirror for companion object Boo
val instanceMirror = rm.reflect(Boo)

// get method symbol for the "hi" method in companion object
val methodSymbolHi = ru.typeOf[Boo.type].decl(ru.TermName("hi")).asMethod

// get method mirror for "hi" method
val methodHi = instanceMirror.reflectMethod(methodSymbolHi)

// invoke the method "hi"
methodHi(4)  // 16
Samar
  • 2,091
  • 1
  • 15
  • 18
2

The Scala 2.13.3 example coding below invokes a common method apply, in two different cases, by finding the companion object refering to the respective example class:

package spielwiese.reflection_versuche

object Structural_Typing_Companion_Object_Invoke_Testframe {

  // Example 1
  case class Person01(vorname: String, name: String)

  object Person01 {
    def apply(x: Integer): Person01 = new Person01(s"Prename_$x", s"Lastname_$x")
  }

  // Example 2
  case class Person02(vorname: String, name: String)

  object Person02 {
    def apply(x: Integer): Person02 = new Person02(s"Prename_$x", s"Lastname_$x")
  }

  // Invocation demo:

  import scala.reflect.runtime.{universe => ru}

  def callGenericCompanionObjectMethod[T](implicit typetag: ru.TypeTag[T]) = {

    val m = ru.runtimeMirror(getClass.getClassLoader)

    val o1 = m.reflectModule(ru.typeOf[T].typeSymbol.companion.asModule).instance

    val o2 = o1.asInstanceOf[{ def apply(x: Integer): T }] // "structural typing"

    o2.apply(123)

  }

  def main(args: Array[String]): Unit = {

    println(callGenericCompanionObjectMethod[Person01]) 
    // prints: "Person01(Prename_123,Lastname_123)"

    println(callGenericCompanionObjectMethod[Person02]) 
    // prints: "Person02(Prename_123,Lastname_123)"

  }

}
Hartmut Pfarr
  • 5,534
  • 5
  • 36
  • 42