If you really have to, you can do it with runtime compilation:
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
def compileCaseClass(name: String, values: (String, String)*): Class[_] = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val code = s"""
|case class $name(${values.map{case (n, t) => n + ": " + t}.mkString(",")})
|scala.reflect.classTag[$name].runtimeClass
""".stripMargin
println(code)
tb.compile(tb.parse(code))().asInstanceOf[Class[_]]
}
Usage example:
val arr = Array("emp_id", "emp_name", "city")
val types = Array.fill(3){"String"}
val emp = compileCaseClass("Emp", (arr zip types): _*)
val inst = emp.getConstructors.head.newInstance("foo", "bar", "baz")
println(inst)
it indeed outputs the usual toString
of a case-class instance:
Emp(foo,bar,baz)
Note that it requires the reflection / compiler toolbox as dependency: it's there if you are running it in the REPL or as a script, but in ordinary projects, you have to add it as separate dependency.