How can I get all vals and subobject vals objects using reflection in Scala?

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 would like to do is something like membersAsHash(classOf[CollectionSettings]) and get the hash) of all the vals that I declared in the object:

 [ Host => "host", Protocol => "protocol", Name => "username", Password => "password", Query => "query", Predicate => "predicate" ] 

It would be nice if the key was a string, even the full name of the package (for example, com.example.Settings.User). I really need values, so if I can only get this, it's still acceptable.

This gave me the name of the subobjects, but I cannot figure out how to get the shafts 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 } 
+6
source share
1 answer

The nice thing is that you use constant value definitions (i.e. finite values ​​without type annotation, see Β§ 4.1 of the specification), so you don't even need 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.declarations.collect { case m: ModuleSymbol => members(m) case m: MethodSymbol if m.isAccessor => m.returnType match { case ConstantType(Constant(s: String)) => Map(m.name.decoded -> s) case _ => Map.empty[String, String] } }.foldLeft(Map.empty[String, String])(_ ++ _) members(typeOf[A].termSymbol) } 

It works as follows:

 scala> deepMembers(Settings) foreach println (Name,username) (Predicate,predicate) (Query,query) (Password,password) (Protocol,protocol) (Host,host) 

If for some reason you cannot use constant value definitions, you will need to adjust the MethodSymbol case to work with instance mirrors, but the basic approach to recursively collecting key-value pairs from child objects will be the same.

+8
source

Source: https://habr.com/ru/post/955025/


All Articles