jeudi 22 novembre 2018

Calling method via reflection in Scala

I want to call an arbitrary public method of an arbitrary stuff via reflection. I.e. let's say, I want to write method extractMethod to be used like:

class User { def setAvatar(avatar: Avatar): Unit = …; … }

val m = extractMethod(someUser, "setAvatar")
m(someAvatar)

From the Reflection. Overview document from Scala docs, I see the following direct way to do that:

import scala.reflect.ClassTag
import scala.reflect.runtime.universe._

def extractMethod[Stuff: ClassTag: TypeTag](
  stuff:      Stuff,
  methodName: String): MethodMirror =
  {
    val stuffTypeTag = typeTag[Stuff]
    val mirror = stuffTypeTag.mirror
    val stuffType = stuffTypeTag.tpe
    val methodSymbol = stuffType
      .member(TermName(methodName)).asMethod
    mirror.reflect(stuff)
      .reflectMethod(methodSymbol)
  }

However what I'm bothered with this solution is that I need to pass implicit ClassTag[Stuff] and TypeTag[Stuff] parameters (first one is needed for calling reflect, second one — for getting stuffType). Which may be quite cumbersome, especially if extractMethod is called from generics that are called from generics and so on. I'd accept this as necessity for some languages that strongly lack runtime type information, but Scala is based on JRE, which allows to do the following:

def extractMethod[Stuff](
  stuff:          Stuff,
  methodName:     String,
  parameterTypes: Array[Class[_]]): (Object*) => Object =
    {
      val unboundMethod = stuff.getClass()
        .getMethod(methodName, parameterTypes: _*)
      arguments => unboundMethod(stuff, arguments: _*)
    }

I understand that Scala reflection allows to get more information that basic Java reflection. Still, here I just need to call a method. Is there a way to somehow reduce requirements (e.g. these ClassTag, TypeTag) of the Scala-reflection-based extractMethod version (without falling back to pure-Java reflection), assuming that performance doesn't matter for me here?





Aucun commentaire:

Enregistrer un commentaire