我需要能够通过反射实例化各种案例类,既可以确定构造函数的参数类型,也可以使用所有默认参数调用构造函数。
我已经做到了这一点:
import reflect.runtime.{universe => ru}
val m = ru.runtimeMirror(getClass.getClassLoader)
case class Bar(i: Int = 33)
val tpe = ru.typeOf[Bar]
val classBar = tpe.typeSymbol.asClass
val cm = m.reflectClass(classBar)
val ctor = tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(ctor)
// figuring out arg types
val arg1 = ctor.paramss.head.head
arg1.typeSignature =:= ru.typeOf[Int] // true
// etc.
// instantiating with given args
val p = ctorm(33)
Run Code Online (Sandbox Code Playgroud)
现在缺少的部分:
val p2 = ctorm() // IllegalArgumentException: wrong number of arguments
Run Code Online (Sandbox Code Playgroud)
那么我如何p2使用 的默认参数创建Bar,即没有反射的情况Bar()。
因此,在链接的问题中,:powerREPL 使用内部 API,这意味着它defaultGetterName不可用,因此我们需要手动构建它。采用@som-snytt 的答案:
def newDefault[A](implicit t: reflect.ClassTag[A]): A = {
import reflect.runtime.{universe => ru, currentMirror => cm}
val clazz = cm.classSymbol(t.runtimeClass)
val mod = clazz.companionSymbol.asModule
val im = cm.reflect(cm.reflectModule(mod).instance)
val ts = im.symbol.typeSignature
val mApply = ts.member(ru.newTermName("apply")).asMethod
val syms = mApply.paramss.flatten
val args = syms.zipWithIndex.map { case (p, i) =>
val mDef = ts.member(ru.newTermName(s"apply$$default$$${i+1}")).asMethod
im.reflectMethod(mDef)()
}
im.reflectMethod(mApply)(args: _*).asInstanceOf[A]
}
case class Foo(bar: Int = 33)
val f = newDefault[Foo] // ok
Run Code Online (Sandbox Code Playgroud)
这真的是最短路径吗?
| 归档时间: |
|
| 查看次数: |
2040 次 |
| 最近记录: |