2013-10-01 10 views
6

Tôi có một đối tượng mà trông như thế này:Làm thế nào tôi có thể nhận được tất cả các đối tượng vals và subobject vals bằng cách sử dụng phản ánh trong Scala?

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

Những gì tôi muốn làm một cái gì đó giống như membersAsHash(classOf[CollectionSettings]) là và nhận một hash) của tất cả các Vals mà tôi đã khai báo trong các đối tượng:

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

Sẽ ổn nếu khóa là một chuỗi, ngay cả tên gói đầy đủ (ví dụ: com.example.Settings.User). Những gì tôi thực sự cần là giá trị, vì vậy nếu tôi chỉ có thể nhận được điều đó, nó vẫn chấp nhận được.

này đã nhận được cho tôi tên của subobjects, nhưng tôi dường như không thể tìm ra cách để có được những Vals đó là nội bộ để mỗi:

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 
} 

Trả lời

8

Điều gọn gàng ở đây là bạn sử dụng định nghĩa giá trị không đổi (ví dụ, giá trị cuối cùng mà không loại chú thích, xem §4.1 của language specification), do đó bạn thậm chí không cần bất kỳ gương:

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

Nó hoạt động như thế này:

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

Nếu vì một số lý do bạn không thể sử dụng định nghĩa giá trị không đổi, bạn sẽ cần phải điều chỉnh trường hợp MethodSymbol để làm việc với gương dụ, nhưng cách tiếp cận cơ bản để đệ quy thu cặp khóa-giá trị từ các đối tượng con sẽ giống nhau.

+0

Điều này cực kỳ hiệu quả. Cảm ơn bạn! –

+0

@TravisBrown: Làm thế nào tôi có thể làm cho nó hoạt động cho các thành viên không phải là thành viên cuối cùng? –

+1

@VenkatSudheerReddyAedama Có lẽ đáng để đặt câu hỏi mới — nếu bạn đăng câu hỏi, tôi có thể thử xem qua tối nay. –

Các vấn đề liên quan