Попробуйте макросы (с Shapeless)
import shapeless.ops.{coproduct, hlist}
import shapeless.{Coproduct, HList, LabelledGeneric}
import shapeless.ops.union.{Keys, Values}
def check[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[C <: Coproduct, K <: HList, V <: Coproduct]()(implicit
labelledGeneric: LabelledGeneric.Aux[A, C],
keys: Keys.Aux[C, K],
values: Values.Aux[C, V],
allKeysStartWithGet: hlist.LiftAll[StartsWithGet, K],
allValuesAreObjects: coproduct.LiftAll[IsObject, V]
) = null
}
import shapeless.Witness
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: Symbol]: StartsWithGet[S] = macro impl[S]
def impl[S <: Symbol : c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[S]
val witness = c.inferImplicitValue(
c.typecheck(tq"_root_.shapeless.Witness.Aux[$typ]", mode = c.TYPEmode).tpe,
silent = false
)
val str = c.eval(c.Expr[Witness.Lt[scala.Symbol]](
c.untypecheck(witness.duplicate)
)).value.name
if (str.startsWith("Get"))
q"new StartsWithGet[$typ] {}"
else c.abort(c.enclosingPosition, s"$str doesn't start with Get")
}
}
trait IsObject[A]
object IsObject {
implicit def mkIsObject[A]: IsObject[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[A]
if (typ.typeSymbol.isModuleClass)
q"new IsObject[$typ] {}"
else c.abort(c.enclosingPosition, s"$typ is not object")
}
}
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
check[Parent]() // compiles
sealed trait Parent
case object GetOne extends Parent
case object Two extends Parent
check[Parent]() // doesn't compile
sealed trait Parent
case object GetOne extends Parent
case class GetTwo() extends Parent
check[Parent]() // doesn't compile