I have a scala code: trait model and its implementation case class Category with custom annotation which i wish to read later
import scala.annotation.StaticAnnotation
class ExtraFields() extends StaticAnnotation
trait Model {}
case class MyCategory( id: Option[Int],
name: String,
level: Option[Int],
@ExtraFields
parent: Option[MyCategory] = None
) extends Model {
}
and i have trait DBModel and its implementation MyCategoryModel. And i pass MyCategory as type parameter to DBModel
trait DBModel[T <: Model] {
lazy val fields = getClassFields[T]
lazy val fields2 = getClassFields2[T]
}
object MyCategoryModel extends DBModel[MyCategory] {
def getFields = fields
def getFields2 = fields2
}
i want trait DBModel to read fields of case class passed as T parameter, so i call two functions
def getClassFields[T] = {
symbolOf[T].asClass.primaryConstructor
.typeSignature.paramLists.head.map {v =>
v.name.toString -> v.annotations
}
}
def getClassFields2[T: TypeTag]: Iterable[(String, List[universe.Annotation])] =
typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor =>
m.name.toString -> m.annotations
}
but none of them is working
val res = MyCategoryModel.getFields // runtime exception: free type T is not a class
val res2 = MyCategoryModel.getFields2 // compile error: No TypeTag available for T
If i call them directly
getClassFields[MyCategory]
getClassFields2[MyCategory]
for a first function i get the same error, for the second i get result but universe.annotations can not see my ExtraFields annotation, returning empty lists for each of fields
Could you please explain this black magic and how to conqure it in my case Thank you
UPD playground https://scastie.scala-lang.org/DTTTyA0CSTSZ0Vj7KFW6Hw
You're missing type class
WeakTypeTag
forgetClassFields
.Additionally, you're not passing the type classes in a trait
DBModel[T <: Model]
.One solution is to define them as context bounds of type
T
. But for this to work, it is required to pass these type classes via a constructor. And because traits do not have constructors, the solution is to useabstract class
.So the following fixes the compilation problems
The method
getClassFields2
is not finding annotations because of the way annotations are specified. If defined as following, both methods work. For more info read meta docs