2013-06-21 9 views
10

Grazie alle risposte a my previous question, sono stato in grado di creare una macro di funzione tale da restituire un valore Map che associa ogni nome di campo al valore di una classe, ad es.Scala Macro: controllo di una determinata annotazione

... 

trait Model 

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

    ... 

    def foo = "bar" 

    ... 
} 

Quindi questo comando

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

myUser.asMap 

rendimenti

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

Questo è dove Tuple s per la Map sono generati (vedi di Travis Brown 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 
} 

... 

Ora voglio ignorare i campi con annotazione @transient. Come dovrei controllare se un metodo ha un'annotazione @transient?

Sto pensando di modificare il frammento di cui sopra come

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 
} 

ma non riesco a trovare quello che ho bisogno di scrivere in exists parte. Come potrei ottenere @transient come Annotation in modo che potessi passarlo lì?

Grazie in anticipo!

risposta

11

L'annotazione sarà sullo val stesso, non sull'accessorio. Il modo più semplice per accedere al val è attraverso il metodo accessed su MethodSymbol:

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

Ora si può semplicemente scrivere il seguente nella vostra collect:

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

Si noti che la versione di isTransient ho dato qui deve essere definito nella tua macro, dal momento che ha bisogno delle importazioni da c.universe, ma puoi farlo un fattore aggiungendo un argomento Universe se stai facendo questo genere di cose in diverse macro.

+1

Grazie ancora! Non riesco a ottenere annotazioni. Ho aggiunto '@ transient' prima di' name' e 'numPosts' nella classe di esempio sopra, ma sono ancora aggiunti alla mappa. Stranamente nessuno dei metodi che hanno attraversato 'isTransient' sembra avere qualche annotazione disponibile. Sia 'm.accessed.annotations' e' m.annotations' sono vuoti. – Emre

+1

Questo è molto strano, funziona per me come previsto in entrambi i casi. Puoi pubblicare il tuo codice esatto? –

+0

Ecco il [codice] (http://pastebin.com/PmW5qg3P). Nota che sto costruendo qualcosa di leggermente diverso qui: una mappa di tutti i campi e tipi di campi di classi di casi in un determinato pacchetto. Il problema non sta avendo un WeakTypeTag? Grazie in anticipo. – Emre

Problemi correlati