Tôi đã thực hiện một số tìm kiếm xung quanh và đã đi kèm với hai giải pháp. Nhận xét, đề xuất, cải tiến được hoan nghênh, tôi đã đánh dấu câu trả lời này là wiki. Mục đầu tiên dựa trên ScalaBeans và ParaNamer.
def valNamesWithAnnotations[T <: AnyRef](obj : T)(implicit m : Manifest[T]) : List[(String, List[java.lang.annotation.Annotation])] = {
val descriptor = descriptorOf(obj.getClass)
val c = descriptor.beanType.erasure
val constructor: Option[Constructor[_]] = {
if (c.getConstructors().isEmpty) None
else Some(c.getConstructors()(0).asInstanceOf[Constructor[_]])
}
val paranamer = new BytecodeReadingParanamer
val ctorParameterNames = constructor.map(paranamer.lookupParameterNames(_)).getOrElse(scala.Array[String]()).toList
val ctorParamAnnos = constructor.getOrElse(sys.error("Cannot find constructor entry for class " + c.getName)).getParameterAnnotations
val builder = List.newBuilder[(String, List[java.lang.annotation.Annotation])]
val paramIter = ctorParameterNames.iterator
val annoIter = ctorParamAnnos.iterator
while(paramIter.hasNext && annoIter.hasNext) {
builder += ((paramIter.next, annoIter.next.toList))
}
builder.result
}
Cách tiếp cận thứ hai sử dụng ScalaSignatures và được dựa trên này SO answer:
def valNamesWithAnnotations[C: ClassManifest] : List[(String, List[java.lang.annotation.Annotation])] = {
val cls = classManifest[C].erasure
val ctors = cls.getConstructors
assert(ctors.size == 1, "Class " + cls.getName + " should have only one constructor")
val sig = ScalaSigParser.parse(cls).getOrElse(sys.error("No ScalaSig for class " + cls.getName + ", make sure it is a top-level case class"))
val classSymbol = sig.parseEntry(0).asInstanceOf[ClassSymbol]
assert(classSymbol.isCase, "Class " + cls.getName + " is not a case class")
val tableSize = sig.table.size
val ctorIndex = (1 until tableSize).find { i =>
sig.parseEntry(i) match {
case m @ MethodSymbol(SymbolInfo("<init>", owner, _, _, _, _), _) => owner match {
case sym: SymbolInfoSymbol if sym.index == 0 => true
case _ => false
}
case _ => false
}
}.getOrElse(sys.error("Cannot find constructor entry in ScalaSig for class " + cls.getName))
val paramsListBuilder = List.newBuilder[String]
for (i <- (ctorIndex + 1) until tableSize) {
sig.parseEntry(i) match {
case MethodSymbol(SymbolInfo(name, owner, _, _, _, _), _) => owner match {
case sym: SymbolInfoSymbol if sym.index == ctorIndex => paramsListBuilder += name
case _ =>
}
case _ =>
}
}
val paramAnnoArr = ctors(0).getParameterAnnotations
val builder = List.newBuilder[(String, List[java.lang.annotation.Annotation])]
val paramIter = paramsListBuilder.result.iterator
val annoIter = paramAnnoArr.iterator
while(paramIter.hasNext && annoIter.hasNext) {
builder += ((paramIter.next, annoIter.next.toList))
}
builder.result
}
Nguồn
2012-07-14 04:29:50
Tùy thuộc vào cách bạn truy cập các tham số này bằng cách phản ánh, bạn có thể phải thêm '@ setter',' @ getter' hoặc '@ param' thay thế hoặc cùng với' @ field'. (Bạn có thể thử với tất cả chúng, và loại bỏ chúng từng người một.) – al3xar