Search code examples
scalacase-class

construct case class from collection of parameters


Given:

case class Thing(a:Int, b:String, c:Double)

val v = Vector(1, "str", 7.3)

I want something that will magically create:

Thing(1, "str", 7.3)

Does such a thing exist (for arbitrary size Things)?


Solution

  • My first time dipping my toes into the 2.10 experimental reflection facilities. So mostly following this outline http://docs.scala-lang.org/overviews/reflection/overview.html, I came up with this:

    import scala.reflect.runtime.{universe=>ru}
    
    case class Thing(a: Int, b: String, c: Double)
    
    object Test {
      def main(args: Array[String]) {
        val v = Vector(1, "str", 7.3)
        val thing: Thing = Ref.runtimeCtor[Thing](v)
        println(thing) // prints: Thing(1,str,7.3)
      }
    }
    
    object Ref {
      def runtimeCtor[T: ru.TypeTag](args: Seq[Any]): T = {
        val typeTag = ru.typeTag[T]
        val runtimeMirror = ru.runtimeMirror(getClass.getClassLoader)
    
        val classSymbol = typeTag.tpe.typeSymbol.asClass
        val classMirror = runtimeMirror.reflectClass(classSymbol)
    
        val constructorSymbol = typeTag.tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
        val constructorMirrror = classMirror.reflectConstructor(constructorSymbol)
        constructorMirrror(args: _*).asInstanceOf[T]
      }
    }
    

    Note that when I had the case class inside the main method, this did not compile. I don't know if type tags can only be generated for non-inner case classes.