I have an object that looks like this:
object Settings {
final val Host = "host"
final val Protocol = "protocol"
object User {
final val Name = "username"
final val Password = "password"
}
object Subject {
final val Query = "query"
final val Predicate = "predicate"
}
}
What I'd like to do is something like membersAsHash(classOf[CollectionSettings])
and receive a hash) of all of the vals that I've declared in the object:
[
Host => "host",
Protocol => "protocol",
Name => "username",
Password => "password",
Query => "query",
Predicate => "predicate"
]
It'd be fine if the key was a string, even the full package name (e.g. com.example.Settings.User). What I really need is the values, so if I can only get that, it's still acceptable.
This has gotten me the name of the subobjects, but I can't seem to figure out how to get the vals that are internal to each:
val optionsToCheck = {
import scala.reflect.runtime.{universe => ru}
val mirror = ru.runtimeMirror(getClass.getClassLoader)
val subObjects = ru.typeOf[CollectionSettings.type].declarations.filter(_.isModule)
subobjects.map(o => mirror.reflectModule(o.asModule).instance.asInstanceOf[Object].toString).toList
}
The neat thing here is that you're using constant value definitions (i.e., final values with no type annotation; see §4.1 of the language specification), so you don't even need any mirrors:
def deepMembers[A: scala.reflect.runtime.universe.TypeTag](a: A) = {
import scala.reflect.runtime.universe._
def members(s: Symbol): Map[String, String] =
s.typeSignature.decls.collect {
case m: ModuleSymbol => members(m)
case m: MethodSymbol if m.isAccessor => m.returnType match {
case ConstantType(Constant(s: String)) => Map(m.name.decodedName.toString -> s)
case _ => Map.empty[String, String]
}
}.foldLeft(Map.empty[String, String])(_ ++ _)
members(typeOf[A].termSymbol)
}
It works like this:
scala> deepMembers(Settings) foreach println
(Name,username)
(Predicate,predicate)
(Query,query)
(Password,password)
(Protocol,protocol)
(Host,host)
If for some reason you couldn't use constant value definitions, you'd need to adjust the MethodSymbol
case to work with instance mirrors,
but the basic approach to recursively collecting key-value pairs from child objects would be the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With