Scala fiddle here
import scala.reflect.ClassTag
import scala.language.existentials
class SomeClass[T <: SomeClass[T, R], R] extends EarlyInit[T, R] {}
trait EarlyInit[T <: SomeClass[T, R], R] {
self: SomeClass[T, R] =>
val clazz = getClass.getSuperclass
val potentialFields = clazz.getDeclaredClasses.toList
potentialFields.foreach {
field => {
// This correctly prints out fields of object members.
// but invokation throws an error every time.
println(s"${field.getName}")
}
}
}
class SomeThing extends SomeClass[SomeThing, Any] {
val stringTest = "test"
object name
object test
}
object SomeThing extends SomeThing {}
val x = SomeThing
How do I access and initialise object members(name
and test
) with reflection?
You can achieve this with scala reflection API:
import scala.reflect.runtime.universe._
class SomeClass[T <: SomeClass[T, R]: TypeTag, R] extends EarlyInit[T] {}
class EarlyInit[T: TypeTag] {
val mirror = runtimeMirror(this.getClass.getClassLoader)
val reflection = mirror.reflect(this)
typeTag[T].tpe.members.filter(_.isModule).foreach(m => reflection.reflectModule(m.asModule).instance)
}
class SomeThing extends SomeClass[SomeThing, Any] {
val stringTest = "test"
object name {
println("name initialized")
}
object test {
println("test initialized")
}
}
object SomeThing extends SomeThing {}
val x = SomeThing
You need to make EarlyInit
a class in order to be able to get a TypeTag
evidence. Then you just search for all modules and access them (they would be initialized in the process)
Update
You can also simplify EarlyInit
a bit and get rid of type parameter. You actually can get a Type
of this
directly from mirror:
trait EarlyInit {
val mirror = runtimeMirror(this.getClass.getClassLoader)
val reflection = mirror.reflect(this)
mirror
.classSymbol(this.getClass)
.toType
.members
.filter(_.isModule)
.foreach(m => reflection.reflectModule(m.asModule).instance)
}