Dowemo

annotation ( note )

Annotation syntax in Scala is similar to Java.
Annotations related to standard library definitions in package scala.annotation.

The basic syntax for annotations is:

@注解名称(注解参数...)


Like the use of Java annotations, annotation parameters aren't required, one element allows multiple annotations.

Custom annotation

Before Scala 2.10, Scala doesn't provide custom annotations, and custom annotations need to be documented.
As part of the Reflect functionality, Scala provides custom annotation support for Scala 2.10.

Like the function, the annotation correlation function is still Expermental ( ), and annotation related API remains in change until the current version ( Scala 2.12 ) is.

A custom annotation in Scala isn't a interface/property, but a.
Custom annotatio & need to be inherited from annotation attributes, and there are two types of annotation attributes in Scala:

  • scala.annotation.ClassfileAnnotation Annotation generated by Java compiler
  • A scala.annotation.StaticAnnotation generated by the Scala compiler

Both annotation attributes inherit from base class scala.annotation.Annotation.
Defining annotation class syntax is the same as normal classes:

//标记注解


class 注解名称 extends StaticAnnotation/ClassfileAnnotation



//有参注解


class 注解名称(参数表...) extends StaticAnnotation/ClassfileAnnotation


Two types of annotation attributes are the same base class, so custom annotation classes allow to mix two types of annotation properties simultaneously.
Annotations inherited from the ClassfileAnnotation base class should be passed in as 具名参数(named arguments) when using the parameter.
Annotation inherited from StaticAnnotation base class no restriction.
As follows:

import scala.annotation.{ClassfileAnnotation, StaticAnnotation}



class CustomStaticAnnotation(name: String) extends StaticAnnotation


class CustomClassfileAnnotation(name: String) extends ClassfileAnnotation



@CustomStaticAnnotation("2333") //正确


@CustomClassfileAnnotation("2333") //错误,Java注解需要以具名参数形式进行传入


@CustomClassfileAnnotation(name = "2333") //正确


class Test


Parsing comments

By the reflection mechanism, the relevant API is located under the scala.reflect.runtime.universe.

Get comments:

  • Gets the annotation of the class:

  • Get class information for Type types using the typeOf() method.
  • Get Symbol through Type.typeSymbol.
  • Get List[Annotation] via Symbol.annotations ( annotation list ).
  • Get the annotation of the method/member field:

  • Get class information for Type types using the typeOf() method.
  • Filter the Symbol of the target member by the Type.decls/decl() method.
  • Get List[Annotation] via Symbol.annotations ( annotation list ).
  • Get the annotation of the method paramete &:

  • Get class information for Type types using the typeOf() method.
  • Filter the MethodSymbol of the target method through the Type.decls/decl() method.
  • Get a parameter table ( List[List[Symbol]] type ) of the target method through the MethodSymbol.paramLists method, which may have more than one parameter table.
  • Get List[Annotation] via Symbol.annotations ( annotation list ).

Scala annotation type scala.reflect.runtime.universe.Annotation .
Before Scala 2.11, the Annotation type provides a scalaArgs/javaArgs such as for annotation information, but in the Scala 2.11 version, these methods have been marked as deprecated.
Annotation syntax tree should be obtained using the Annotation.tree method. scala.reflect.runtime.universe.Tree .

As follows:

import scala.annotation.StaticAnnotation


import scala.reflect.runtime.universe._



class CustomAnnotation(name: String, num: Int) extends StaticAnnotation



@CustomAnnotation("Annotation for Class", 2333)


class Test {


 @CustomAnnotation("Annotation for Class", 6666)


 val ff = ""


}



object Main extends App {



 {


 //获取类型注解


 val tpe: Type = typeOf[Test]


 val symbol: Symbol = tpe.typeSymbol //获取类型符号信息


 val annotation: Annotation = symbol.annotations.head


 val tree: Tree = annotation.tree //获取语法树



 //解析注解语法树...


 }



 {


 //获取成员字段注解


 val tpe: Type = typeOf[Test]


 val symbol: Symbol = tpe.decl(TermName("ff")) //获取字段符号信息


 val annotation: Annotation = symbol.annotations.head


 val tree: Tree = annotation.tree



 //解析注解语法树...


 }



}


Through through scala.reflect.api.Printer.showRaw() Method to get the text of the syntax tree.
Annotation syntax tree contai & annotation parameter information that can be extracted by pattern matching.

As follows:

import scala.annotation.StaticAnnotation


import scala.reflect.runtime.universe._



class CustomAnnotation(name: String, num: Int) extends StaticAnnotation



@CustomAnnotation("Annotation for Class", 2333)


class Test



object Main extends App {



 //获取类型注解


 val tpe: Type = typeOf[Test]


 val symbol: Symbol = tpe.typeSymbol //获取类型符号信息


 val annotation: Annotation = symbol.annotations.head


 val tree: Tree = annotation.tree //获取语法树



 println(showRaw(tree)) //打印语法树


 val Apply(_, Literal(Constant(name: String)) :: Literal(Constant(num: Int)) :: Nil) = tree


 println(s"Annotation args: name -> $name, num -> $num")



}


Output results: ( Scala 2.12.2 && macOS 10.12.5 )

Apply(Select(New(TypeTree()), termNames.CONSTRUCTOR), List(Literal(Constant("Annotation for Class")), Literal(Constant(2333))))


Annotation args: name -> Annotation for Class, num -> 2333


Co ideratio:

  • Parsing annotation paramete & requires a syntax tree based on a syntax tree that doesn't use the xargs parameter default value to build the syntax tree that uses the default paramete & that don't contain the default values for annotation information.
  • There are more than one TermSymbol in the class field, which corresponds to a different TermName that contains the TermName of the annotation.
  • The constructor parameter of the sample class exists as a member of the class, but the annotation information isn't attached to the field information.
    Extract the annotation information for the sample class constructor member to get the method parameter annotation, find the constructor method ( TermName("<init>") ), get the
  • Get the annotation syntax tree ( Tree type ) using the Annotation.tree method, and then use the Tree.tpe method to get annotation syntax tree type information ( Type type ), which is the same as the annotation type information directly obtained using typeOf[注解类型], which can be used to compare the type of annotation.

The complete annotation parsing I & tance, as follows:

import scala.annotation.StaticAnnotation


import scala.reflect.runtime.universe._



class CustomAnnotation(name: String, num: Int) extends StaticAnnotation {


 override def toString = s"Annotation args: name -> $name, num -> $num"


}



@CustomAnnotation("Annotation for Class", 2333)


class Test {


 @CustomAnnotation("Annotation for Member", 6666)


 val ff = ""


 def mm(ss: String, @CustomAnnotation("Annotation for Arg", 9999) arg: Int) = ""


}



object Main extends App {



 //获取指定类型的注解信息,通过 Annotation.tree.tpe 获取注解的 Type 类型,以此进行筛选


 def getClassAnnotation[T: TypeTag, U: TypeTag] =


 symbolOf[T].annotations.find(_.tree.tpe =:= typeOf[U])



 //通过字段名称获取指定类型的注解信息,注意查找字段名称时添加空格


 def getMemberAnnotation[T: TypeTag, U: TypeTag](memberName: String) =


 typeOf[T].decl(TermName(s"$memberName")).annotations.find(_.tree.tpe =:= typeOf[U])



 //通过方法名称和参数名称获取指定类型的注解信息


 def getArgAnnotation[T: TypeTag, U: TypeTag](methodName: String, argName: String) =


 typeOf[T].decl(TermName(methodName)).asMethod.paramLists.collect {


 case symbols => symbols.find(_.name == TermName(argName))


 }.headOption.fold(Option[Annotation](null))(_.get.annotations.find(_.tree.tpe =:= typeOf[U]))



 //解析语法树,获取注解数据


 def getCustomAnnotationData(tree: Tree) = {


 val Apply(_, Literal(Constant(name: String)) :: Literal(Constant(num: Int)) :: Nil) = tree


 new CustomAnnotation(name, num)


 }



 getClassAnnotation[Test, CustomAnnotation].map(_.tree) foreach { classAnnotationTree =>


 val classAnnotation = getCustomAnnotationData(classAnnotationTree)


 println(classAnnotation)


 }



 getMemberAnnotation[Test, CustomAnnotation]("ff").map(_.tree) foreach { memberAnnotationTree =>


 val memberAnnotation = getCustomAnnotationData(memberAnnotationTree)


 println(memberAnnotation)


 }



 getArgAnnotation[Test, CustomAnnotation]("mm", "arg").map(_.tree) foreach { argAnnotationTree =>


 val argAnnotation = getCustomAnnotationData(argAnnotationTree)


 println(argAnnotation)


 }



}


Output results: ( Scala 2.12.2 && macOS 10.12.5 )

Annotation args: name -> Annotation for Class, num -> 2333


Annotation args: name -> Annotation for Member, num -> 6666


Annotation args: name -> Annotation for Arg, num -> 9999





Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs