samedi 18 juin 2016

Cast inherited annotation represented by runtime.Annotation to its parent type

I want to use these parent and child annotations to build reports from case classes:

@scala.annotation.meta.field
class RatingField[T](msg: T => String, isCorrectWhen: T => Boolean) extends StaticAnnotation  

@scala.annotation.meta.field
class BooleanRatingField(msg: String => String) extends RatingField[Boolean](x => msg(if (x) "true" else "false")), x => x)

As you can see, fields annotated with these annotations are associated with:

  • msg lambda (to build a string from each of them);
  • isCorrectWhen lambda (says if field is "correct" or "incorrect").

BooleanRatingField was written to let developer not to write x => x and if (x) "true" else "false") for every boolean field.

For example, the case class itself is

case class MyCaseClass(@RatingField[String](f => s"strParam: $f", _.contains("abc"))
                       strParam: String,
                       @BooleanRatingField(f => s"---boolParam: $f---")
                       boolParam: Boolean,
                       @RatingField[Int](f => s"===intParam: $f===", _ > 100)
                       intParam: Int)

Now I get and print types of these annotations:

import scala.reflect.runtime.universe.{Annotation, typeOf}

typeOf[MyCaseClass]
  .members
  .collect { case symbol if symbol.isTerm => symbol.asTerm }
  .collect { case term if term.isVal || term.isVar => term.annotations }
  .flatMap { annotationsList => annotationsList.find { a: Annotation => a.tree.tpe <:< typeOf[RatingField[_]] } }
  .map(_.tree.tpe)
  .toSeq
  .reverse
  .foreach(println)

The result is:

MainObject.RatingField[String]

MainObject.BooleanRatingField

MainObject.RatingField[Int]

The problem is that BooleanRatingField does not contain isCorrectWhen lambda so I would like to see it as its parent RatingField[Boolean]. Is there any way to do this cast?





Aucun commentaire:

Enregistrer un commentaire