Emre
Emre

Reputation: 1043

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!

Upvotes: 11

Views: 1259

Answers (1)

Travis Brown
Travis Brown

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

Related Questions