Try
import scala.reflect.runtime.universe._
import scala.reflect.runtime
trait BaseTrait {
def myMethod: String
}
object MyObject extends BaseTrait {
override def myMethod: String = "MyObject.myMethod"
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val moduleSymbol = typ.termSymbol.asModule
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val runtimeMirror = runtime.currentMirror
val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[MyObject.type] // MyObject.myMethod
If the object is nested into a class try
class Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = moduleSymbol.owner.asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = runtimeMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror() // if class Outer has no-arg constructor
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod
If Outer
is a trait (abstract class) rather than class you can use Toolbox
trait Outer {
object `_` extends BaseTrait {
override def myMethod: String = "_.myMethod"
}
}
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
toolbox.eval(q"(new $outerClassSymbol).`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
or
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
val toolboxMirror = toolbox.mirror
val moduleSymbol = typ.termSymbol.asModule
val outerClassSymbol = toolbox.define(
q"class OuterImpl extends com.example.Outer".asInstanceOf[ClassDef]
).asClass
val outerClassType = outerClassSymbol.typeSignature
val outerConstructorSymbol = outerClassType.decl(termNames.CONSTRUCTOR).asMethod
val outerClassMirror = toolboxMirror.reflectClass(outerClassSymbol)
val outerConstructorMirror = outerClassMirror.reflectConstructor(outerConstructorSymbol)
val outerInstance = outerConstructorMirror()
val outerInstanceMirror = runtimeMirror.reflect(outerInstance)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = toolboxMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
val outer = new Outer {}
invokeMyMethod[outer.`_`.type] // _.myMethod
Or if you can use existing instance of the outer class/trait try
val outer = new Outer
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val runtimeMirror = runtime.currentMirror
val moduleSymbol = typ.termSymbol.asModule
val outerInstanceMirror = runtimeMirror.reflect(outer)
val moduleMirror = outerInstanceMirror.reflectModule(moduleSymbol)
val methodSymbol = typ.decl(TermName("myMethod")).asMethod
val instance = moduleMirror.instance
val instanceMirror = runtimeMirror.reflect(instance)
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
methodMirror().asInstanceOf[String]
}
invokeMyMethod[outer.`_`.type] // _.myMethod
Actually you can use outer
deconstructing the input type
def invokeMyMethod[T: TypeTag]: String = {
val typ = typeOf[T]
val outerSymbol = typ match {
case SingleType(pre, _) => pre.termSymbol
}
val runtimeMirror = runtime.currentMirror
val toolbox = runtimeMirror.mkToolBox()
toolbox.eval(q"$outerSymbol.`_`.myMethod").asInstanceOf[String]
}
val outer = new Outer
invokeMyMethod[outer.`_`.type] // _.myMethod