Question

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
Was it helpful?

Solution

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....

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top