Suppose I have a MyItem
trait and its companion object has an apply()
function that creates a class instance called SubItem
that extends from MyItem
:
import scala.reflect.runtime.{universe => ru}
trait MyItem {
import MyItem._
def num: Option[Int]
}
object MyItem {
class SubItem(val num: Option[Int]) extends MyItem
def apply(num: Option[Int]): MyItem = new SubItem(num) // creates SubItem
}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
val modifiedItem = MyItem(Some(11))
val theType = getTypeTag(modifiedItem).tpe
If you print out theType
above, it will be MyItem
.
At this point if you try to use reflection to modify the field num
, it's not going to work because MyItem
has num
as a method, not a field (as in MyItem.SubItem
):
val m = ru.runtimeMirror(modifiedItem.getClass.getClassLoader)
val numTermSymb = theType.decl(ru.TermName("num")).asTerm
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectField(numTermSymb) // not going to work
numFieldMirror.get
numFieldMirror.set(Some(999)) // my goal, if possible
Unfortunately, above will throw out scala.ScalaReflectionException: expected a field or an accessor method symbol, you provided method num
.
Instead you should do the following:
val numTermSymb = theType.decl(ru.TermName("num")).asMethod
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectMethod(numTermSymb)
numFieldMirror() // returns `Some(11)`
But my goal is to access the SubItem class that extends MyItem and modify its field. How can I get an instance of the type MyItem
and modify the field in MyItem.SubItem
that MyItem
's method num
is accessing?
Replace
with
if you know the name of class statically or with
if you know the name of class dynamically.
Try
Actually,
m.staticClass(className).typeSignature
isAnyRef with pckg.MyItem {...}
i.e. parents/decls ofSubItem
so, although
numFieldMirror.get/set
work, it's better to usetoType
instead oftypeSignature
One more way is purely Scala-like
It's even better because doesn't use error-prone and implementation-dependent operations on strings (
replace
).