动态创建案例类 [英] Dynamically create case class
问题描述
我正在使用一个 csv 库,它接受一个 case 类并将其转换为行供我阅读.
I am using a csv library that takes a case class and turns it into rows for me to read.
语法非常接近 File(path).asCsvReader[caseClass]
.链接到图书馆here
The syntax is pretty close to File(path).asCsvReader[caseClass]
.
Link to library here
但是问题是我想从数据库中的表生成我的案例类.我可以接收数据库中的表和列的类型(Int、Long、Double、String 等),但我不知道如何使用该数据动态创建案例类,因为我不知道编译时的信息.
However the problem is that I want to generate my case class from the tables in my database. I can receive the tables in my database and the types that the columns are (Int, Long, Double, String etc) but I do not know how to dynamically create a case class with that data since I do not know the information at compile time.
正因为如此,我也不能使用宏,因为我不知道宏编译时的表数据.
It is because of this that I can't use macros either since I do not know the table data at the compile time of the macro.
那么,一旦我收到表数据,然后将该案例类传递给 csv 库,我将如何动态创建此案例类?
So how would I go about dynamically creating this case class once I receive the table data and then passing that case class to the csv library?
推荐答案
With hints from dveim in 这个答案,我添加了第二个解决方案,它适用于 Scala 2.10 和 2.11 并使用 Scala 工具箱.不幸的是,生成的案例类在默认包中.
With hints from dveim in this answer, I'm adding a second solution that works both in Scala 2.10 and 2.11 and uses Scala Toolbox. The generated cases classes unfortunately are in the default package.
/**
* Generate a case class and persist to file
* Can't add package to the external class
* @param file External file to write to
* @param className Class name
* @param header case class parameters
*/
def writeCaseClass(file: File, className: String, header: String): Unit = {
val writer: PrintWriter = new PrintWriter(file)
writer.println("case class " + className + "(")
writer.println(header)
writer.println(") {}")
writer.println("\nscala.reflect.classTag[" + className + "].runtimeClass")
writer.flush()
writer.close()
}
使用工具箱编译外部类
/**
* Helper method to search code files in directory
* @param dir Directory to search in
* @return
*/
def recursiveListFiles(dir: File): Array[File] = {
val these = dir.listFiles
these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles)
}
/**
* Compile scala files and keep them loaded in memory
* @param classDir Directory storing the generated scala files
* @throws IOException if there is problem reading the source files
* @return Map containing Class name -> Compiled Class Reference
*/
@throws[IOException]
def compileFiles(classDir: String): Map[String, Class[_]] = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val files = recursiveListFiles(new File(classDir))
.filter(_.getName.endsWith("scala"))
println("Loaded files: \n" + files.mkString("[", ",\n", "]"))
files.map(f => {
val src = Source.fromFile(f).mkString
val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]
getClassName(f.getName) -> clazz
}).toMap
}
实例化和使用已编译的类
编译后的类可以从地图中获取并在必要时使用,例如
Instantiate and Use compiled classes
The compiled class can be obtained from the map and used where necessary e.g.
//Test Address class
def testAddress(map: Map[String, Class[_]]) = {
val addressClass = map("AddressData")
val ctor = addressClass.getDeclaredConstructors()(0)
val instance = ctor.newInstance("123 abc str", "apt 1", "Hello world", "HW", "12345")
//println("Instantiated class: " + instance.getClass.getName)
println(instance.toString)
}
这篇关于动态创建案例类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!