动态创建案例类 [英] Dynamically create case class

查看:49
本文介绍了动态创建案例类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆