Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Macros: Checking for a certain annotation

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 Tuples 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!

like image 854
Emre Avatar asked Jun 21 '13 13:06

Emre


1 Answers

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.

like image 199
Travis Brown Avatar answered Oct 18 '22 11:10

Travis Brown