How to invoke method on companion object via reflection?

后端 未结 3 1723
长发绾君心
长发绾君心 2020-12-16 23:39

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:

Cl         


        
相关标签:
3条回答
  • 2020-12-17 00:20

    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)"
    
      }
    
    }
    
    0 讨论(0)
  • 2020-12-17 00:23

    For case when you have only Type of Foo (in question is foo):

    % scala
    Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 15-loom).
    Type in expressions for evaluation. Or try :help.
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    import scala.reflect.runtime.currentMirror
    import scala.reflect.runtime.universe._
    import scala.reflect.runtime.universe.definitions._
    
    def f(tpe: Type): Unit = {
      val m = currentMirror
      val im = m.reflect(
        m.reflectModule(tpe.typeSymbol.asClass.companion.asModule).instance
      )
      val method = tpe.companion.decl(TermName("name")).asMethod
      val v = im.reflectMethod(method)("John", "Doe")
      println(v)
    }
    
    // Exiting paste mode, now interpreting.
    
    import scala.reflect.runtime.currentMirror
    import scala.reflect.runtime.universe._
    import scala.reflect.runtime.universe.definitions._
    f: (tpe: reflect.runtime.universe.Type)Unit
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    case class Foo()
    case object Foo { def name(fn: String, ln: String): String = s"$fn $ln" }
    
    // Exiting paste mode, now interpreting.
    
    defined class Foo
    defined object Foo
    
    scala> f(typeOf[Foo])
    John Doe
    
    0 讨论(0)
  • 2020-12-17 00:28

    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
    
    0 讨论(0)
提交回复
热议问题