lundi 12 octobre 2020

Troubles with getting case class fields via reflection

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





Aucun commentaire:

Enregistrer un commentaire