Scala Macro:使用Option类型创建新类
发布时间:2020-12-16 08:44:12 所属栏目:安全 来源:网络整理
导读:我想写一个宏给出这个: @MetaRest case class User( @get id : Int,@get @post @patch name : String,@get @post email : String,registeredOn : DateTime) 生成以下代码: object User { case class Get(id: Int,name: String,email: String) case class P
我想写一个宏给出这个:
@MetaRest case class User( @get id : Int,@get @post @patch name : String,@get @post email : String,registeredOn : DateTime ) 生成以下代码: object User { case class Get(id: Int,name: String,email: String) case class Post(name: String,email: String case class Patch(name: Option[String]) // Note - the Option type here! } 我在这里取得了不错的进展:https://github.com/pathikrit/metarest 这是我的尝试:https://github.com/pathikrit/metarest/blob/master/src/main/scala/com/github/pathikrit/MetaRest.scala class MetaRest extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro MetaRest.impl } object MetaRest { sealed trait MethodAnnotations extends StaticAnnotation class get extends MethodAnnotations class put extends MethodAnnotations class post extends MethodAnnotations class patch extends MethodAnnotations def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ def modifiedCompanion(compDeclOpt: Option[ModuleDef],className: TypeName,fields: List[ValDef]) = { val result = fields.flatMap {field => field.mods.annotations.collect { // TODO: shorten this - make use of the fact that all extend sealed trait MethodAnnotations case q"new get" => "get" -> field case q"new put" => "put" -> field case q"new post" => "post" -> field case q"new patch" => "patch" -> field } } groupBy (_._1) mapValues(_ map (_._2.duplicate)) println(result("get")) // TODO: ---------------------------------------------------------------------------------------- val getRequestModel = q"""case class Get(id: Int,email: String)""" val postRequestModel = q"""case class Post(name: String,email: String)""" val patchRequestModel = q"""case class Patch(name: Option[String])""" // ------------------------------------------------------------------------------------------------ compDeclOpt map { compDecl => val q"object $obj extends ..$bases { ..$body }" = compDecl q""" object $obj extends ..$bases { ..$body $getRequestModel $postRequestModel $patchRequestModel } """ } getOrElse { q""" object ${className.toTermName} { $getRequestModel $postRequestModel $patchRequestModel } """ } } def modifiedDeclaration(classDecl: ClassDef,compDeclOpt: Option[ModuleDef] = None) = { val q"case class $className(..$fields) extends ..$bases { ..$body }" = classDecl val compDecl = modifiedCompanion(compDeclOpt,className,fields) c.Expr(q""" $classDecl $compDecl """) } annottees.map(_.tree) match { case (classDecl: ClassDef) :: Nil => modifiedDeclaration(classDecl) case (classDecl: ClassDef) :: (compDecl: ModuleDef) :: Nil => modifiedDeclaration(classDecl,Some(compDecl)) case _ => c.abort(c.enclosingPosition,"@MetaRest must annotate a class") } } } 测试在这里:https://github.com/pathikrit/metarest/blob/master/src/test/scala/com/github/pathikrit/MetaRestSpec.scala 通过注释对字段进行干净分组并生成Get / Post类的最佳方法是什么?此外,对于Patch类 – 如何将所有字段转换为Option [original.type]? 解决方法
其实我做到了:
https://github.com/pathikrit/metarest/commit/1d1af92b71179385c8521d00a5059dd21996c448?diff=split 这很简单: q"$accessor val $vname: $tpe" => q"$accessor val $vname: Option[$tpe]" (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |