How to create annotations and get them in scala

2020-02-03 06:10发布

问题:

I want to define some annotations and use them in Scala.

I looked into the source of Scala, found in scala.annotation package, there are some annotations like tailrec, switch, elidable, and so on. So I defined some annotations as them do:

class A extends StaticAnnotation

@A
class X {
    @A
    def aa() {}
}

Then I write a test:

object Main {
    def main(args: Array[String]) {
        val x = new X
        println(x.getClass.getAnnotations.length)
        x.getClass.getAnnotations map { println }
    }
}

It prints some strange messages:

1
@scala.reflect.ScalaSignature(bytes=u1" !1* 1!AbCaE
9"a!Q!! 1gn!!.<b    iBPE*,7
    Ii#)1oY1mC&1'G.Y(cUGCa#=S:LGO/AA!A  1mI!)

Seems I can't get the annotation aaa.A.

How can I create annotations in Scala correctly? And how to use and get them?

回答1:

Could it have something to do with retention? I bet @tailrec is not included in the bytecode getting generated.

If I try to extend ClassfileAnnotation (in order to have runtime retention), Scala tells me that it can't be done, and it has to be done in Java:

./test.scala:1: warning: implementation restriction: subclassing Classfile does not
make your annotation visible at runtime.  If that is what
you want, you must write the annotation class in Java.
class A extends ClassfileAnnotation
      ^


回答2:

FWIW, you can now define scala annotation in scala 2.10 and use reflection to read them back.

Here are some examples: Reflecting Annotations in Scala 2.10



回答3:

I think you can only define annotations in Java now.

http://www.scala-lang.org/node/106



回答4:

You can find a nice description of how annotations are to be used in Scala in Programming Scala.

So you can define or use annotations in scala. However there is at least one limitation:

Runtime retention is not quite possible. In theory you should subclass ClassFileAnnotation to achieve this, but currently scalac reports the following warning if you do it:

"implementation restriction: subclassing Classfile does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java."

It also means that your code is fine as it is (at least as fine as it is currently possible in Scala), but the annotation is on the class only during compile time. So you could use it e.g. in compiler plugins, but you will not be able to access it runtime.



回答5:

With scala 2.11.6, this works to extract values of a annotation:

case class MyAnnotationClass(id: String) extends scala.annotation.StaticAnnotation

val myAnnotatedClass: ClassSymbol = u.runtimeMirror(Thread.currentThread().getContextClassLoader).staticClass("MyAnnotatedClass")
val annotation: Option[Annotation] = myAnnotatedClass.annotations.find(_.tree.tpe =:= u.typeOf[MyAnnotationClass])
val result = annotation.flatMap { a =>
  a.tree.children.tail.collect({ case Literal(Constant(id: String)) => doSomething(id) }).headOption
}