Skip to content

Instantly share code, notes, and snippets.

@ConnorDoyle
Last active January 26, 2022 20:00
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save ConnorDoyle/7002426 to your computer and use it in GitHub Desktop.
Save ConnorDoyle/7002426 to your computer and use it in GitHub Desktop.
Generic reflective case class instantiation with Scala 2.10.x
package test
import scala.reflect.runtime.universe._
object ReflectionHelpers extends ReflectionHelpers
trait ReflectionHelpers {
protected val classLoaderMirror = runtimeMirror(getClass.getClassLoader)
/**
* Encapsulates functionality to reflectively invoke the constructor
* for a given case class type `T`.
*
* @tparam T the type of the case class this factory builds
*/
class CaseClassFactory[T: TypeTag] {
val tpe = typeOf[T]
val classSymbol = tpe.typeSymbol.asClass
if (!(tpe <:< typeOf[Product] && classSymbol.isCaseClass))
throw new IllegalArgumentException(
"CaseClassFactory only applies to case classes!"
)
val classMirror = classLoaderMirror reflectClass classSymbol
val constructorSymbol = tpe.declaration(nme.CONSTRUCTOR)
val defaultConstructor =
if (constructorSymbol.isMethod) constructorSymbol.asMethod
else {
val ctors = constructorSymbol.asTerm.alternatives
ctors.map { _.asMethod }.find { _.isPrimaryConstructor }.get
}
val constructorMethod = classMirror reflectConstructor defaultConstructor
/**
* Attempts to create a new instance of the specified type by calling the
* constructor method with the supplied arguments.
*
* @param args the arguments to supply to the constructor method
*/
def buildWith(args: Seq[_]): T = constructorMethod(args: _*).asInstanceOf[T]
}
}
//////////////////////////////////////////////////////////////////////////////
// USAGE
//////////////////////////////////////////////////////////////////////////////
case class Person(name: String, age: Int)
val personFactory = new ReflectionHelpers.CaseClassFactory[Person]
val result: Person = personFactory.buildWith(Seq("Connor", 27))
val expected = Person("Connor", 27)
assert(result == expected)
@charmby
Copy link

charmby commented Aug 15, 2017

Person is a class, not a String

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