Reputation: 3
Given the name of a class, method and parameters from a third party library, how to create an object and invoke its method using scala reflection?
For example, the class name is "org.apache.spark.mllib.clustering.LDA", the method is "setK" and the parameter is 3, how to use scala reflection to construct a LDA object and invoke method? The result should be equivalent to new LDA().setK(3)
.
In scala reflection document, I found the following code to construct a Person object
val m = ru.runtimeMirror(getClass.getClassLoader)
val classPerson = ru.typeOf[Person].typeSymbol.asClass
val ctor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(ctor)
val p = ctorm("Mike")
but what if I have the "Person" instead of the Person class?
Upvotes: 0
Views: 687
Reputation: 170735
I have to agree with Luis in the comments that you should strongly consider other approaches, but in case this does turn out to be what you need:
// for the example
val className = "org.apache.spark.mllib.clustering.LDA"
val methodName = "setK"
val constructorParams = Array()
val params = Array(3)
// symbols
val m = ru.runtimeMirror(getClass.getClassLoader)
val classSymbol = m.staticClass(className)
val ctor = classSymbol.primaryConstructor.asMethod
// assumes the method exists and isn't overloaded
val method = classSymbol.toType.decl(ru.TermName(methodName)).asMethod
val cm = m.reflectClass(classSymbol)
val ctorm = cm.reflectConstructor(ctor)
val instance = ctorm(constructorParams: _*)
val instancem = m.reflect(instance)
val methodm = instancem.reflectMethod(method)
methodm(params: _*)
Or for this particular task you can just find that using Java reflection is simpler and Scala reflection provides no real advantage:
val clazz = Class.forName(className)
val ctor = clazz.getConstructors()(0)
val instance = ctor.newInstance(constructorParams: _*)
// again, assumes the method exists and isn't overloaded
val method = clazz.getMethods().find(_.getName == methodName).get
method.invoke(instance, params: _*)
Upvotes: 1
Reputation: 51658
Try
import org.apache.spark.mllib.clustering.LDA
import scala.reflect.runtime.{universe => ru}
val m = ru.runtimeMirror(getClass.getClassLoader)
val classLDA = ru.typeOf[LDA].typeSymbol.asClass
val ctor = ru.typeOf[LDA].decl(ru.termNames.CONSTRUCTOR).asMethod
val cm = m.reflectClass(classLDA)
val ctorm = cm.reflectConstructor(ctor)
val p = ctorm.asInstanceOf[LDA]
p.setK(3)
Upvotes: 1