2013-06-21 91 views
10

感謝my previous question的答案,我能夠創建一個函數宏,以便它返回一個Map,它將每個字段名稱映射到一個類的值,例如,斯卡拉宏:檢查某個註釋

... 

trait Model 

case class User (name: String, age: Int, posts: List[String]) extends Model { 
    val numPosts: Int = posts.length 

    ... 

    def foo = "bar" 

    ... 
} 

所以這個命令

val myUser = User("Foo", 25, List("Lorem", "Ipsum")) 

myUser.asMap 

回報

Map("name" -> "Foo", "age" -> 25, "posts" -> List("Lorem", "Ipsum"), "numPosts" -> 2) 

這是產生Tuple S爲Map(見特拉維斯布朗的answer):

... 

val pairs = weakTypeOf[T].declarations.collect { 
    case m: MethodSymbol if m.isAccessor => 
    val name = c.literal(m.name.decoded) 
    val value = c.Expr(Select(model, m.name)) 
    reify(name.splice -> value.splice).tree 
} 

... 

現在我想忽略具有@transient註釋的字段。如何檢查方法是否有@transient註釋?

我想修改爲

val pairs = weakTypeOf[T].declarations.collect { 
    case m: MethodSymbol if m.isAccessor && !m.annotations.exists(???) => 
     val name = c.literal(m.name.decoded) 
     val value = c.Expr(Select(model, m.name)) 
     reify(name.splice -> value.splice).tree 
} 

上面的代碼片段,但我無法找到我所需要的exists部分來寫。我如何獲得@transient作爲Annotation,所以我可以通過它?

在此先感謝!

回答

11

註釋將在val本身上,而不是在存取器上。訪問val最簡單的方法就是通過accessed方法上MethodSymbol

def isTransient(m: MethodSymbol) = m.accessed.annotations.exists(
    _.tpe =:= typeOf[scala.transient] 
) 

現在你可以只寫在你的collect如下:

case m: MethodSymbol if m.isAccessor && !isTransient(m) => 

注意的isTransient版本我已經給這裏必須在你的宏中定義,因爲它需要從c.universe進口,但是如果你在幾個宏中做這種事情,你可以通過添加一個Universe參數來分解它。

+1

再次感謝!我似乎無法獲得註釋。我在上面的示例類的'name'和'numPosts'之前添加了'@ transient',但它們仍然添加到地圖中。奇怪的是,通過'isTransient'的方法似乎沒有任何註釋可用。 'm.accessed.annotations'和'm.annotations'都是空的。 – Emre

+1

這很奇怪 - 它適用於我在兩種情況下的預期。你可以發佈你的確切代碼嗎? –

+0

這是[code](http://pastebin.com/PmW5qg3P)。請注意,我在這裏構建的東西略有不同 - 一個給定包下的case類的所有字段和字段類型的映射。問題沒有WeakTypeTag?提前致謝。 – Emre