Instantiating a case class with default args via reflection

后端 未结 4 1525
孤街浪徒
孤街浪徒 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:49

    This is the most complete example how to create case class via reflection with default constructor parameters(Github source):

    import scala.reflect.runtime.universe
    import scala.reflect.internal.{Definitions, SymbolTable, StdNames}
    
    object Main {
      def newInstanceWithDefaultParameters(className: String): Any = {
        val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)
        val ds = universe.asInstanceOf[Definitions with SymbolTable with StdNames]
        val classSymbol = runtimeMirror.staticClass(className)
        val classMirror = runtimeMirror.reflectClass(classSymbol)
        val moduleSymbol = runtimeMirror.staticModule(className)
        val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
        val moduleInstanceMirror = runtimeMirror.reflect(moduleMirror.instance)
        val defaultValueMethodSymbols = moduleMirror.symbol.info.members
          .filter(_.name.toString.startsWith(ds.nme.defaultGetterName(ds.newTermName("apply"), 1).toString.dropRight(1)))
          .toSeq
          .reverse
          .map(_.asMethod)
        val defaultValueMethods = defaultValueMethodSymbols.map(moduleInstanceMirror.reflectMethod).toList
        val primaryConstructorMirror = classMirror.reflectConstructor(classSymbol.primaryConstructor.asMethod)
        primaryConstructorMirror.apply(defaultValueMethods.map(_.apply()): _*)
      }
    
      def main(args: Array[String]): Unit = {
        val instance = newInstanceWithDefaultParameters(classOf[Bar].getName)
        println(instance)
      }
    }
    
    case class Bar(i: Int = 33)
    

提交回复
热议问题