I've used the accepted answer of this question to build little helper class to construct case classes from arrays of values: construct case class from collection of parameters
As mentioned in the answer, inner case classes don't work. You get a
ScalaReflectionException: class X is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror
I'm having trouble figuring out how to use an InstanceMirror as the exception explains. Here's my current REPL-able code (slightly more complex than needed because of the cache).
import scala.reflect.runtime.universe._
object ReflectUtil {
private val constructorCache = collection.mutable.HashMap[String, MethodMirror]()
def constructFromSeq[T: TypeTag](args: Seq[Any]): T = {
val tag = typeTag[T]
val strTag = tag.toString
var constructorMirror = constructorCache.getOrElseUpdate( strTag, {
val rm = runtimeMirror(getClass.getClassLoader)
val classSymbol = tag.tpe.typeSymbol.asClass
val classMirror = rm.reflectClass(classSymbol) // wrap with try/catch?
val constructorSymbol = tag.tpe.declaration(nme.CONSTRUCTOR).asMethod
classMirror.reflectConstructor(constructorSymbol)
})
constructorMirror(args: _*).asInstanceOf[T]
}
}
case class X(a:String, b:Int)
class Out {
case class Y(a:String, b:Int)
def buildY(arr:Array[Any]) = {
ReflectUtil.constructFromSeq[Y](arr)
}
}
val arr = Array[Any]("asdf", 1234)
ReflectUtil.constructFromSeq[X](arr) // this works
val inst = new Out
inst.buildY(arr) // this doesn't work
What exception implies is that you need an outer reference to construct an instance of an inner class (e.g. to construct Y
you need an instance of Out
). Then you could do rm.reflect(instanceOfOut).reflectClass...
.