Я не могу найти, как получить доступ к членам объекта РЕКУРСИВНО, не зная / не указывая их типы. В моем случае проблема ограничена членами lazy val
s и object
, к которым я хочу получить доступ. Объекты могут быть вложены на любую глубину с lazy vals
, присутствующими в них. Например:
object TestShallow {
lazy val value1 = 1
}
object TestDeep {
lazy val value1 = 1
object NestedObj {
lazy val value2 = 2
}
}
Вот что у меня есть:
import scala.reflect.ClassTag
import scala.reflect.runtime.universe._
def evalMemberValues[A: TypeTag](topLevelObj: A)(implicit c: ClassTag[A]): Unit = {
val mirror = runtimeMirror(getClass.getClassLoader)
def loop[B: TypeTag](obj: B)(implicit c: ClassTag[B]): Unit = {
println(s"INSPECTING: $obj: ${typeOf[B]}")
val members = typeOf[B].decls.filter(_.isPublic)
members.foreach { m =>
if(m.isTerm && m.isModule) {
println(s"MODULE: $m")
// THE PROBLEM IS HERE !!!:
val inst = mirror.reflectModule(m.asModule).instance // type is Any
loop(inst)
}
else if(m.isTerm && ! m.isConstructor && m.isMethod && m.typeSignature.paramLists.isEmpty && ! m.typeSignature.takesTypeArgs) {
val im = mirror.reflect(obj)
val value = im.reflectMethod(m.asMethod)()
println(s"VAL/DEF: $m = $value")
}
else {
println(s"OTHERS: $m")
}
}
}
loop(topLevelObj)
}
Отлично работает для объявлений первого уровня:
scala> evalMemberValues(TestShallow)
INSPECTING: $line7.$read$$iw$$iw$$iw$$iw$TestShallow$@1669f4e5: TestShallow.type
OTHERS: constructor TestShallow
VAL/DEF: lazy value value1 = 1
Тем не менее, он не может рекурсивно корректно:
scala> evalMemberValues(TestDeep)
INSPECTING: $line11.$read$$iw$$iw$$iw$$iw$TestDeep$@3c2f310c: TestDeep.type
OTHERS: constructor TestDeep
VAL/DEF: lazy value value1 = 1
MODULE: object NestedObj
INSPECTING: $line11.$read$$iw$$iw$$iw$$iw$TestDeep$NestedObj$@4f1f2f84: Any
OTHERS: method ==
OTHERS: method !=
OTHERS: method equals
OTHERS: method hashCode
OTHERS: method toString
OTHERS: method getClass
OTHERS: method isInstanceOf
OTHERS: method asInstanceOf
OTHERS: method ##
Как видите, проблема в этой строке:
val inst = mirror.reflectModule(m.asModule).instance
потому что он дает мне экземпляр типа Any
и информация теряется. В идеале я хотел бы получить экземпляр с деталями TypeTag
и ClassTag
правильного типа, который соответствует m
. Я не нашел, как получить это из Symbol
, то есть m
, я думаю, компилятор не сгенерирует это. Я также не вижу, как его разыграть, используя instanceOf[_]
. Может быть, я мог бы получить декларации / членов другим способом? Все примеры, которые я нашел, не получают тип экземпляра динамически и не восстанавливают экземпляр для получения объявлений следующего уровня.
Кроме того, как лучше проверить Symbol
, то есть val
или lazy val
? Я вижу такие проверки только в ModuleSymbol
: isVal
, isLazy
, что для меня немного странно.