上下文:
我正在为在Scala中使用JMX开发一个库。其中一个目标是为ManagedBeans提供一个强类型接口。我想类似于Spring框架JMX库。
目标:将表格数据沙漠化为案例类别的宏:
// interface for which I'd like to generate an implementation using a macro
trait JMXTabularAssembler[T <: Product] {
def assemble(data: TabularData): T
}
object JMXAnnotations {
case class Attribute(name: String) extends StaticAnnotation
}
case class example(
@Attribute("name") name: String,
@Attribute("age") age: Int,
unmarked: String
)
问题:有很多使用q""
插值器组成树的例子。但我不知道如何使用tq""
插值器从类型上下文中提取case类中的字段。
private def mkAssembler[T <: Product : c.WeakTypeTag](c: Context): c.universe.Tree = {
import c.universe._
val tt = weakTypeOf[T]
}
问题:我如何使用QuasiQuote机制来销毁我的case类的字段,以便我可以在它们上循环并用我的注释筛选出字段(我的Attribute
注释在我目前采用的方法中不可用">(。下面的实现按声明顺序返回带有注释的字段就是我想要的。
private def harvestFieldsWithAnnotations[T<: Product: c.WeakTypeTag](c: Context):
List[(c.universe.Name, String, c.universe.Type, List[c.universe.Annotation])] = ???
奖励:目标是获取属性字段,为每个字段生成从TabularData
中提取字段的树,并使用这些树创建JMXTabularAssembler
函数。如果你能向我展示如何为上面的例子做到这一点,它将引导我的努力:D。
我所尝试的:我开始用反思来解决问题。这似乎不是正确的方法。代码段:
...
val dec = tt.decls.sorted
def getFields = dec.withFilter( t=> t.isTerm && ! t.isMethod)
def getCaseAccessors = dec.withFilter( t => t.isMethod && t.asMethod.isCaseAccessor)
dec.foreach { d=>
println(d.name, d.annotations)
}
getFields.foreach { f =>
println(f.annotations)
}
val types = getCaseAccessors.map { d =>
println(d.annotations)
(d.name, tt.member(d.name).asMethod.returnType)
}
...
下面的方法做到了这一点,它不使用准引号。关键是访问表示事例类的字段访问器的符号的后备字段(accessed
调用(。
private def harvestFieldsWithAnnotations[T <: Product : c.WeakTypeTag](c: Context) = {
import c.universe._
val tt = weakTypeOf[T]
tt.decls.sorted.filter(t => t.isMethod && t.asMethod.isCaseAccessor).map { ca =>
val asMethod = tt.member(ca.name).asMethod
(ca.name, asMethod.returnType, asMethod.accessed.annotations)
}
}
除非用scala.annotation.meta.field
显式注释字段注释,否则字段注释不会被保留。
因此Attribute
注释应该是:
@field
case class Attribute(name: String) extends StaticAnnotation