从具有特定注释的Scala案例类中获取字段名称

时间:2017-04-13 16:46:03

标签: scala reflection annotations

final class ContactInfo extends StaticAnnotation{}

case class Person(val id: String,
              val firstName: String,
              val lastName: String,
              @ContactInfo val phoneNumbers: Seq[String],
              @ContactInfo val email: String)

def getContactInfoFields[T: TypeTag]: Seq[String] = {
???
}

预期输出getContactInfoFields [Person] =(“phoneNumbers”,“email”)

Riffing off the answer to a similar question on SO我试过了

def getContactInfoFields[T: TypeTag]: Seq[String] = {
  val fields = typeOf[T].members.collect{ case s: TermSymbol => s }.
    filter(s => s.isVal || s.isVar)

  fields.filter(_.annotations.exists(_.isInstanceOf[ContactInfo]))
    .map(x=>x.name.toString).toSeq
}

然而在实践中,这将返回一个空序列。我错过了什么?

2 个答案:

答案 0 :(得分:1)

您可以在类型级别表示此信息。

sealed trait ContactInfo
case class PhoneNumbers(numbers: Seq[String]) extends ContactInfo
case class Email(email: String) extends ContactInfo

case class Person(id: String, firstName: String, lastName: String, phoneNumbers: PhoneNumbers, email: Email)

def contactInfo[T: TypeTag] = typeOf[T].members.filter(!_.isMethod).map(_.typeSignature).collect {
  case t if t <:< typeOf[ContactInfo] => t.typeSymbol.name.toString
}

致电contactInfo[Person]返回Iterable[String] = List(Email, PhoneNumbers)

答案 1 :(得分:1)

感谢大家的帮助!我设法提出了一个有效的解决方案。事实证明,我试图将JavaUniverse.reflection.Types与Scala Universe反射类型进行比较,这就是过滤器语句失败的原因。以下函数按预期返回

def listContactInfoFields(symbol: TypeSymbol): Seq[String] = {

  val terms = symbol.asClass.primaryConstructor.typeSignature.paramLists.head

  val annotatedFields = terms.filter(_.annotations.exists(_.tree.tpe =:= typeOf[ContactInfo]))

  annotatedFields.map(_.name.toString)
}