2013-10-01 8 views
6

Mam obiekt, który wygląda tak:Jak mogę uzyskać wszystkie obiekty vals i podobiektów vals za pomocą odbicia w Scali?

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" 
    } 
} 

Co chciałbym zrobić coś takiego jak membersAsHash(classOf[CollectionSettings]) i otrzymać hash) od wszystkich Vals, że mam zadeklarowanych w obiekcie:

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

Byłoby dobrze, gdyby klucz był ciągiem, nawet pełną nazwą pakietu (np. Com.example.Settings.User). To, czego naprawdę potrzebuję, to wartości, więc jeśli mogę to tylko uzyskać, to jest to do przyjęcia.

ten dostał mi imię podobiektów, ale nie może wydawać się, aby dowiedzieć się jak uzyskać Vals, które są ze sobą wewnętrzny:

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 
} 

Odpowiedz

8

Schludny rzeczą jest to, że jesteś stosując Definicje wartość stała (czyli wartości końcowe bez adnotacji typu patrz §4.1 z language specification), więc nawet nie trzeba żadnych luster:

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) 
} 

to działa tak:

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

Jeśli z jakiegoś powodu nie może korzystać z definicji wartość stałą, którą trzeba dostosować sprawę MethodSymbol pracować z lustrami przykład ale podstawowe podejścia do rekurencyjnie zbierania pary klucz-wartość z obiektami dziecko być takim samym.

+0

To było bardzo skuteczne. Dziękuję Ci! –

+0

@TravisBrown: Jak mogę sprawić, aby działał on na rzecz członków niebędących członkami końcowymi? –

+1

@VenkatSudheerReddyAedama Prawdopodobnie warte nowego pytania - jeśli napiszesz jedną, mogę spróbować spojrzeć tego wieczoru. –