为Scio类型安全的动态读/写创建Scala case类

hgncfbus  于 7个月前  发布在  Scala
关注(0)|答案(1)|浏览(48)

我尝试动态生成Scala类,然后在Scio对GCP BigQuery的读/写中将其用作安全类型。
目标示例:

import com.spotify.scio.bigquery._
import com.spotify.scio.bigquery.types.BigQueryType

@BigQueryType.fromTable("dataset.SOURCE_TABLE")
class SOURCE_TABLE

@BigQueryType.toTable
case class TARGET_TABLE(id: String, name: String, desc: String)

def main(cmdlineArgs: Array[String]): Unit = {
  val (sc, args) = ContextAndArgs(cmdlineArgs)
  sc.typedBigQuery[SOURCE_TABLE]()  // Read from BQ
    .map( row => transformation(row) ) // Transform -> SCollection[TARGET_TABLE]
    .saveAsTypedBigQueryTable(Table.Spec(args("TARGET_TABLE")))  // save to BQ
  sc.run()
  ()
}

字符串
作为输入,有dataset,SOURCE_TABLE,TARGET_TABLE,目标字段列表,所以我可以建立一个生成类的字符串源。所有这些值都是从其他第三方(json,xml等)动态检索的,并且可以在每次执行时可变。
因此,生成类的源代码可以表示为:

val sourceString =
  s"""
     |import com.spotify.scio.bigquery.types.BigQueryType
     |
     |@BigQuery.fromTable("$dataset.$SOURCE_TABLE")
     |class $SOURCE_TABLE
     |
   """.stripMargin

val targetString =
  s"""
     |import com.spotify.scio.bigquery.types.BigQueryType
     |
     |@BigQueryType.toTable
     |case class $TARGET_TABLE($fieldDefinitions)
   """.stripMargin


这些源代码被认为是转换为类,这些类型是Scio BigQuery I/O所需的。
Scala版本:2.12.17
我尝试使用Scala运行时的Mirror和Python(从this answer,从this,等等)。但是所有的变体都抛出相同的错误:***enable macro paradise(2.12)或-Ymacro-annotations(2.13)来扩展宏注解***很明显Python的内部编译器看不到 build.sbt 设置:

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)


除此之外,here提到,here并不打算用于如此复杂的事情。
因此,我决定使用scala.tools.nsc包来应用一种方法,就像this answer中描述的那样,但是它抛出了同样的错误,即缺少宏注解。
因此,主要问题是:是否有机会将所需的编译器插件设置添加到scala.tools.nsc.{Global, Settings}或应用任何其他方法来动态生成此类注解类?

def compileCode(sources: List[String], classpathDirectories: List[AbstractFile], outputDirectory: AbstractFile): Unit = {
  val settings = new Settings
  classpathDirectories.foreach(dir => settings.classpath.prepend(dir.toString))
  settings.outputDirs.setSingleOutput(outputDirectory)
  settings.usejavacp.value = true
  //*****
  // Add macros paradise compiler plugin?
  //*****
  val global = new Global(settings)
  val files = sources.zipWithIndex.map { case (code, i) => new BatchSourceFile(s"(inline-$i)", code) }
  (new global.Run).compileSources(files)
}

5anewei6

5anewei61#

您可以通过馈送相应的命令行选项来打开工具箱的天堂插件

import scala.reflect.runtime
import scala.tools.reflect.ToolBox
val rm = runtime.currentMirror

val tb = rm.mkToolBox(options = "-Xplugin:/path/to/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalamacros/paradise_2.12.18/2.1.1/paradise_2.12.18-2.1.1.jar")

字符串
在Scala 2.12或

val tb = rm.mkToolBox(options = "-Ymacro-annotations")


在Scala 2.13中。
如果你更喜欢实际的编译器而不是工具箱,那么你可以用下面的方式提供这个选项

settings.plugin.value = List("/path/to/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalamacros/paradise_2.12.18/2.1.1/paradise_2.12.18-2.1.1.jar")


在Scala 2.12或

settings.YmacroAnnotations.value = true


在Scala 2.13中。

相关问题