Skip to content

Instantly share code, notes, and snippets.

@igreenfield
Last active February 17, 2016 15:44
Show Gist options
  • Save igreenfield/c6f18249d16cd163df99 to your computer and use it in GitHub Desktop.
Save igreenfield/c6f18249d16cd163df99 to your computer and use it in GitHub Desktop.
Util to do projection on case classes
object TestApp extends App {
val temp = Temp("a", "b", List(1, 2, 3, 4))
val psetUtils: PsetUtils = new PsetUtils(classOf[Temp])
println("line 1: " + psetUtils.toMap(temp, List("a", "c")))
println("line 2: " + psetUtils.toMap(temp, List("a")))
println("line 3: " + psetUtils.toMap(temp, List("b")))
println("line 4: " + psetUtils.toMap(temp, List("c")))
println("line 5: " + psetUtils.toMap(temp, List("c", "a", "b")))
}
/*
OUTPUT:
line 1: Map(a -> a, c -> List(1, 2, 3, 4))
line 2: Map(a -> a)
line 3: Map(b -> b)
line 4: Map(c -> List(1, 2, 3, 4))
line 5: Map(c -> List(1, 2, 3, 4), a -> a, b -> b)
*/
import scala.reflect.runtime.universe._
class PsetUtils(types: Class[_ <: Product]*) {
private val mirror = runtimeMirror(getClass.getClassLoader)
/**
* extract the field name from the class type and store them in Map[String, Map[String, Int]]
* the second Int is the index of the field in the Object.
*/
private val fieldsDeclaration = types.map(tg => tg.getSimpleName ->
mirror.classSymbol(tg).toType.members
.filter(_.isInstanceOf[MethodSymbol])
.filter(_.asInstanceOf[MethodSymbol].isCaseAccessor).map {
case m: MethodSymbol =>
m.name.toString
}.toList.reverse.zipWithIndex.toMap
).toMap
/**
* Convert the object to map with the fields you pass in.
*/
def toMap(obj: AnyRef, fields: List[String]): Map[String, Any] = {
val className = obj.getClass.getSimpleName
fieldsDeclaration.get(className) match {
case None => Map.empty[String, Any]
case Some(declaration) => {
fields.map(name => {
val fieldIndex = declaration(name)
name -> obj.asInstanceOf[Product].productElement(fieldIndex)
}).toMap
}
}
}
}
case class Temp(a: String, b: String, c: List[Int])
@yairogen
Copy link

can you add a bit of documentation internally to better explain your different steps?

@igreenfield
Copy link
Author

@yairogen I add comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment