Reputation: 1043
Thanks to the answers to my previous question, I was able to create a function macro such that it returns a Map
that maps each field name to its value of a class, e.g.
...
trait Model
case class User (name: String, age: Int, posts: List[String]) extends Model {
val numPosts: Int = posts.length
...
def foo = "bar"
...
}
So this command
val myUser = User("Foo", 25, List("Lorem", "Ipsum"))
myUser.asMap
returns
Map("name" -> "Foo", "age" -> 25, "posts" -> List("Lorem", "Ipsum"), "numPosts" -> 2)
This is where Tuple
s for the Map
are generated (see Travis Brown's 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
}
...
Now I want to ignore fields that have @transient
annotation. How would I check if a method has a @transient
annotation?
I'm thinking of modifying the snippet above as
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
}
but I can't find what I need to write in exists
part. How would I get @transient
as an Annotation
so I could pass it there?
Thanks in advance!
Upvotes: 11
Views: 1259
Reputation: 139028
The annotation will be on the val
itself, not on the accessor. The easiest way to access the val
is through the accessed
method on MethodSymbol
:
def isTransient(m: MethodSymbol) = m.accessed.annotations.exists(
_.tpe =:= typeOf[scala.transient]
)
Now you can just write the following in your collect
:
case m: MethodSymbol if m.isAccessor && !isTransient(m) =>
Note that the version of isTransient
I've given here has to be defined in your macro, since it needs the imports from c.universe
, but you could factor it out by adding a Universe
argument if you're doing this kind of thing in several macros.
Upvotes: 11