Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Finds all case classes under a given package, finds their val declarations and creates a function that returns a Map out of them which corresponds
- * to their field values and field types.
- *
- * Example:
- * package model
- *
- * case class User(name: String, age: Int, posts: List[Post]) {
- * val numPosts = posts.length
- * }
- *
- * case class Post(content: String)
- *
- * For this package, allCaseClassFields("model") should return something along the lines of:
- * Map(
- * User -> List( ("name", String), ("age", Int), ("posts", List[Post]), ("numPosts", Int) )
- * Post -> List( ("content", String) )
- * )
- *
- */
- def allCaseClassFields_impl(c: Context)(packageName: c.Expr[String]) = {
- import c.universe._
- def isTransient(m: MethodSymbol) = {
- m.accessed.annotations.exists(_.tpe =:= typeOf[scala.transient])
- }
- // Get package name from the expression tree
- val Literal(Constant(name: String)) = packageName.tree
- // Get all classes under given package name
- val classes = c.mirror.staticPackage(name).typeSignature.declarations
- // Obtain types for the classes
- val types = classes.collect {
- case s: ClassSymbol if (s.isCaseClass) => s.toType
- }
- // Apply method for List. For easy readability in later applications
- val listApply = Select(reify(List).tree, newTermName("apply"))
- /*
- * We get an iterable of (class -> List((value, class), ...) here.
- * Basically what we do here is this:
- * For all types,
- * For all members of types,
- * If the member is an accessor method (i.e. val getter), then construct a tuple (field_name, return_type)
- * The expression above returns an Iterable called members.
- * Construct a List out of members.
- * Construct a mapping type_name -> members.
- * The expression above returns an iterable called result.
- * Construct a Map out of result.
- *
- */
- val result = types.map { t =>
- val members = t.declarations.collect {
- case m: MethodSymbol if m.isAccessor && !isTransient(m) =>
- val name = c.literal(m.name.decoded)
- val tpe = c.Expr(Literal(Constant(m.returnType)))
- reify((name.splice, tpe.splice)).tree
- }
- val membersExpr = c.Expr[List[Tuple2[String, Class[_]]]](Apply(listApply, members.toList))
- val typeName = c.Expr[Any](Literal(Constant(t)))
- reify(typeName.splice -> membersExpr.splice).tree
- }
- val mapApply = Select(reify(Map).tree, newTermName("apply"))
- c.Expr[Map[Class[_], List[Tuple2[String, Class[_]]]]](Apply(mapApply, result.toList))
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement