2
case class FieldName(field: String) extends scala.annotation.StaticAnnotation
@FieldName("foo") trait Foo
import scala.reflect.runtime.universe._

symbolOf[Foo].annotations.head
// ann: Annotation = FieldName("type")

How do I access the annotation as a FieldName object? The doc mentions tree.children.tail, but there's no types to be had.

Reactormonk
  • 21,472
  • 14
  • 74
  • 123

1 Answers1

3

If you really want the instance of FieldName the best I can think of is using a ToolBox:

scala> case class FieldName(field: String) extends scala.annotation.StaticAnnotation
defined class FieldName

scala> @FieldName("foo") trait Foo
defined trait Foo

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> val annotation = symbolOf[Foo].annotations.head
annotation: reflect.runtime.universe.Annotation = FieldName("foo")

scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox

scala> val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@1b26a499

scala> tb.eval(tb.untypecheck(annotation.tree)).asInstanceOf[FieldName]
res10: FieldName = FieldName(foo)

With .tree.children.tail you can access the arguments passed to FieldName without creating the actual instance.

scala> annotation.tree.children.tail.map{ case Literal(Constant(field)) => field } 
res11: List[Any] = List(foo)

If you just want all FieldName annotations and extract their value, you can do this:

scala> val fields = symbolOf[Foo].annotations.withFilter( 
     |   a => a.tree.tpe <:< typeOf[FieldName] 
     | ).flatMap( 
     |   a => a.tree.children.tail.map{ case Literal(Constant(field)) => field } 
     | )
fields: List[Any] = List(foo)
Jasper-M
  • 14,966
  • 2
  • 26
  • 37
  • May be a bit of XY - accessing by type would make sure I don't catch any other annotations by mistake. But it would actually be sufficient to check it's the correct annotation and extracting the value. – Reactormonk Mar 09 '17 at 16:16
  • @Reactormonk Oh ok, I see what you mean now. – Jasper-M Mar 09 '17 at 16:26
  • If I have more than one annotation, how can I know which fields belong to which annotation? – bashan Apr 29 '17 at 09:13
  • The ToolBox method works, but is terribly slow, which renders it unusable for my purposes. Is there a way to make it faster? – raimohanska Oct 30 '17 at 13:21
  • 1
    @raimohanska I think you'll just have to extract `field` manually, and if you really need a `FieldName` instance just reconstruct it from the extracted `field`. – Jasper-M Oct 30 '17 at 18:28
  • @bashan With `a.tree.tpe <:< typeOf[FieldName]` you can check whether the annotation you're processing is a `FieldName` or not. – Jasper-M Oct 30 '17 at 18:34