功能:用 宏注解实现一个 为case class 生成get set 方法 注解
github 地址:https://github.com/1178615156/use-scala-macro-annotation-make-get-set
//功能如下
@MakeGetSet case class Hello( var a: String, var int: Int, var option: Option[String], var none: Option[AnyRef] = None, val hello: Boolean = true ) object Main { def main(args: Array[String]) { val a = new Hello("a", 1, Some("option")) //a.a println(a.getA)//a //a.int println(a.getInt)//1 //return option.getOrElse(null) println(a.getOption)//option //return option.getOrElse(null) println(a.getNone)//null //a.none=Option(Some("")) a.setNone(Some("")) println(a.none)//Some(Some()) //a.none=Some("") a.none = Some("") println(a.none)//Some() println(a.getHello)//true //no have this method because hello is val //a.setHello(false ) } }
宏 的实现代码 :
import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros import scala.annotation.{compileTimeOnly, StaticAnnotation} /** * Created by YuJieShui on 2015/9/4. */ @compileTimeOnly("") class MakeGetSet extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro AnnotationGetSetMacroImpl.impl } class AnnotationGetSetMacroImpl(val c: Context) { import c.universe._ //get case class def getInCaseClass(list_annottees: List[Tree]) = list_annottees match { case caseClass :: Nil => caseClass case caseClass :: companionObject :: Nil => caseClass } def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { val inCaseClass = getInCaseClass(annottees.map(_.tree).toList) val out: c.universe.Tree = inCaseClass match { //if inCaseClass no a case class //throw match error case q"case class $name(..$params) extends ..$bases { ..$body }" => val list_params: List[ValDef] = params.asInstanceOf[List[ValDef]] val get_set_params_func = list_params.map((param: c.universe.ValDef) => { //get method name val get_name = TermName("get" + { val vn = param.name.toString; vn.head.toString.toUpperCase() + vn.tail }) //set method name val set_name = TermName("set" + { val vn = param.name.toString; vn.head.toString.toUpperCase() + vn.tail }) param match { case ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) => val v_type: c.universe.Tree = tq"$tpt" //如果参数类型为泛型参数 v_type.children.headOption.map { // where type is Option[_] case tq"Option" => Tuple2( q"""@..${mods.annotations} def $get_name = $name.orNull """, //where value is var //make set method if (mods.hasFlag(Flag.MUTABLE)) q"def $set_name(sss:${v_type.children(1)}):Unit=this.${name}=Option(sss)" else q"" ) //other such : Future[_],List[_] case _ => Tuple2( q"def $get_name = ${param.name}", q"" ) } //非泛型参数 .getOrElse(Tuple2( q"def $get_name= {${param.name}}", if (mods.hasFlag(Flag.MUTABLE)) q"def $set_name(sss:$v_type):Unit=this.${name}=sss" else q"" )) } }).flatMap(t2 => List(t2._1, t2._2)) q""" case class $name(..$params) extends ..$bases { ..$get_set_params_func ..$body } """ } c.Expr(out) } }