Instantiating a case class with default args via reflection

后端 未结 4 1474
孤街浪徒
孤街浪徒 2021-01-24 04:03

I need to be able to instantiate various case classes through reflection, both by figuring out the argument types of the constructor, as well as invoking the constructor with al

4条回答
  •  旧巷少年郎
    2021-01-24 04:28

    So in the linked question, the :power REPL uses internal API, which means that defaultGetterName is not available, so we need to construct that from hand. An adoption from @som-snytt 's answer:

    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
    

    Is this really the shortest path?

提交回复
热议问题