2013-06-21 7 views
10

Dank der Antworten auf my previous question konnte ich ein Funktionsmakro so erstellen, dass es eine Map zurückgibt, die jeden Feldnamen auf seinen Wert einer Klasse abbildet, z.Scala-Makros: Überprüfung auf eine bestimmte Annotation

... 

trait Model 

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

    ... 

    def foo = "bar" 

    ... 
} 

So dieser Befehl

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

myUser.asMap 

kehrt

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

Hier Tuple s für die Map erzeugt werden (siehe 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 
} 

... 

Jetzt möchte ich Felder ignorieren, die @transient Annotation haben. Wie würde ich prüfen, ob eine Methode eine @transient Annotation hat?

Ich denke, das Snippet oben als

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

aber ich kann nicht finden, was ich in exists Teil schreiben müssen. Wie würde ich @transient als Annotation bekommen, damit ich es dort übergeben könnte?

Vielen Dank im Voraus!

Antwort

11

Die Anmerkung wird auf dem val selbst, nicht auf dem Accessor sein. Der einfachste Weg, um die val ist durch die accessed Methode auf MethodSymbol zuzugreifen:

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

Jetzt können Sie einfach schreiben folgend in collect:

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

Beachten Sie, dass die Version von isTransient mir gegeben habe Hier muss in Ihrem Makro definiert werden, da es die Importe von c.universe benötigt, aber Sie könnten es ausschließen, indem Sie ein Universe Argument hinzufügen, wenn Sie diese Art von Sache in mehreren Makros ausführen.

+1

Danke nochmal! Ich kann anscheinend keine Anmerkungen erhalten. Ich habe '@ transient' vor 'name' und' numPosts' in der obigen Beispielklasse hinzugefügt, aber sie werden immer noch zur Karte hinzugefügt. Seltsamerweise scheint keine der Methoden, die "isTransient" durchlaufen hat, irgendwelche Anmerkungen verfügbar zu haben. Sowohl "m.accessed.annotations" als auch "m.annotations" sind leer. – Emre

+1

Das ist sehr seltsam - es funktioniert für mich wie erwartet in beiden Fällen. Kannst du vielleicht deinen genauen Code posten? –

+0

Hier ist der [code] (http://pastebin.com/PmW5qg3P). Beachten Sie, dass ich hier etwas etwas anderes baue - eine Karte aller Felder und Feldtypen von Fallklassen unter einem gegebenen Paket. Hat das Problem keinen WeakTypeTag? Danke im Voraus. – Emre

Verwandte Themen