Scala SBT如何使用DataNucleus从模型类生成元模型类?

Scala SBT如何使用DataNucleus从模型类生成元模型类?,scala,sbt,datanucleus,metamodel,Scala,Sbt,Datanucleus,Metamodel,如何从持久性模型类(如客户端、产品、发票)生成元模型类(如QClient、QProduct、QInvoice),以便使用JDOQL类型安全查询 特别是,我感兴趣的是生成元模型类,并通过SBT和使用带有JDO注释的DataNucleus在持久性类上运行字节码增强 这个问题与有关 简而言之,您需要在build.sbt中定义函数,这些函数执行元模型和字节码增强的生成,如下所示: def generateQueryEntities(sourcepath: File,

如何从持久性模型类(如客户端、产品、发票)生成元模型类(如QClient、QProduct、QInvoice),以便使用JDOQL类型安全查询

特别是,我感兴趣的是生成元模型类,并通过SBT和使用带有JDO注释的DataNucleus在持久性类上运行字节码增强


这个问题与
有关

简而言之,您需要在
build.sbt
中定义函数,这些函数执行元模型和字节码增强的生成,如下所示:

def generateQueryEntities(sourcepath: File,
                          sources: Seq[File],
                          generated: File,
                          classes: File,
                          classpath: Seq[File],
                          javacOptions: Seq[String]): Seq[File] = {
  IO.createDirectory(generated)
  javaRunner(
    javaTool = Option("javac"),
    args =
      javacOptions ++
        (if(debug) Seq("-verbose") else Seq.empty[String]) ++
        Seq(
          "-sourcepath", sourcepath.absolutePath,
          "-s",  generated.absolutePath,
          "-d",  classes.absolutePath) ++
        sources.map(p => p.absolutePath),
    classpath = Option(classpath),
    cwd = Option(classes)
  )
  classes.listFiles.filter(f => f.isFile && (f.ext == "class"))
}

def enhanceSchema(classes: File, classpath: Seq[File]): Seq[File] = {
  javaRunner(
    mainClass = Option("javax.jdo.Enhancer"),
    args =
      (if(debug) Seq("-v") else Seq.empty[String]) ++
      Seq(
        "-pu", "code-generation",
        "-d",  classes.absolutePath),
    classpath = Option(classpath),
    cwd = Option(classes)
  )
  classes.listFiles.filter(f => f.isFile && (f.ext == "class"))
}
lazy val model =
  project.in(file("model"))
    .settings(publishSettings:_*)
    .settings(librarySettings:_*)
    .settings(paranoidOptions:_*)
    .settings(otestFramework: _*)
    .settings(deps_resolvers:_*)
    //XXX .settings(deps_langtools:_*)
    .settings(deps_tagging:_*)
    .settings(deps_stream:_*)
    .settings(deps_database:_*)
    .settings(managedSources:_*)
    .settings(
      Seq(
        // generate JDOQL Entities
        genjdoql in Compile := {
          generateQueryEntities(
            sourcepath = (javaSource in Compile).value,
            sources = (unmanagedSources in Compile).value,
            generated = baseDirectory.value / "target" / scalav(scalaVersion.value) / "src_managed" / "main"  / "java",
            classes = (classDirectory in Compile).value,
            classpath = (managedClasspath in Compile).value.files,
            javacOptions = javacOpts :+ "-AqueryMode=PROPERTY"
          )},
        sourceGenerators in Compile <+= genjdoql in Compile,
        // prevent javac from running annotation processors
        javacOptions ++= Seq( "-proc:none" ),
        // perform bytecode enhancement
        manipulateBytecode in Compile := {
          val previous = (manipulateBytecode in Compile).value
          enhanceSchema(
            classes = (classDirectory in Compile).value,
            classpath =
              (managedClasspath in Compile).value.files ++
                (unmanagedResourceDirectories in Compile).value :+
                (classDirectory in Compile).value)
          previous
        }
      ):_*)
    .dependsOn(util)
下一步包括为这些函数定义自定义任务。我们只需要如下所示的
genjdoql
,因为字节码增强可以通过子任务
manufacteByteCode
连接。请注意,
SBT 0.13.8
或更高版本是必需的

val genjdoql      = TaskKey[Seq[File]]("genjdoql",    "DataNucleus JDOQL Entities")
然后,您需要在项目或模块的构建中连接这些函数,如下所示:

def generateQueryEntities(sourcepath: File,
                          sources: Seq[File],
                          generated: File,
                          classes: File,
                          classpath: Seq[File],
                          javacOptions: Seq[String]): Seq[File] = {
  IO.createDirectory(generated)
  javaRunner(
    javaTool = Option("javac"),
    args =
      javacOptions ++
        (if(debug) Seq("-verbose") else Seq.empty[String]) ++
        Seq(
          "-sourcepath", sourcepath.absolutePath,
          "-s",  generated.absolutePath,
          "-d",  classes.absolutePath) ++
        sources.map(p => p.absolutePath),
    classpath = Option(classpath),
    cwd = Option(classes)
  )
  classes.listFiles.filter(f => f.isFile && (f.ext == "class"))
}

def enhanceSchema(classes: File, classpath: Seq[File]): Seq[File] = {
  javaRunner(
    mainClass = Option("javax.jdo.Enhancer"),
    args =
      (if(debug) Seq("-v") else Seq.empty[String]) ++
      Seq(
        "-pu", "code-generation",
        "-d",  classes.absolutePath),
    classpath = Option(classpath),
    cwd = Option(classes)
  )
  classes.listFiles.filter(f => f.isFile && (f.ext == "class"))
}
lazy val model =
  project.in(file("model"))
    .settings(publishSettings:_*)
    .settings(librarySettings:_*)
    .settings(paranoidOptions:_*)
    .settings(otestFramework: _*)
    .settings(deps_resolvers:_*)
    //XXX .settings(deps_langtools:_*)
    .settings(deps_tagging:_*)
    .settings(deps_stream:_*)
    .settings(deps_database:_*)
    .settings(managedSources:_*)
    .settings(
      Seq(
        // generate JDOQL Entities
        genjdoql in Compile := {
          generateQueryEntities(
            sourcepath = (javaSource in Compile).value,
            sources = (unmanagedSources in Compile).value,
            generated = baseDirectory.value / "target" / scalav(scalaVersion.value) / "src_managed" / "main"  / "java",
            classes = (classDirectory in Compile).value,
            classpath = (managedClasspath in Compile).value.files,
            javacOptions = javacOpts :+ "-AqueryMode=PROPERTY"
          )},
        sourceGenerators in Compile <+= genjdoql in Compile,
        // prevent javac from running annotation processors
        javacOptions ++= Seq( "-proc:none" ),
        // perform bytecode enhancement
        manipulateBytecode in Compile := {
          val previous = (manipulateBytecode in Compile).value
          enhanceSchema(
            classes = (classDirectory in Compile).value,
            classpath =
              (managedClasspath in Compile).value.files ++
                (unmanagedResourceDirectories in Compile).value :+
                (classDirectory in Compile).value)
          previous
        }
      ):_*)
    .dependsOn(util)
lazy-val模型=
project.in(文件(“模型”))
.settings(publishSettings:u*)
.设置(库设置:u*)
.设置(选项:*)
.设置(otestFramework:*)
.设置(deps_解析器:*)
//XXX.设置(deps_langtools:u*)
.设置(deps_标记:*)
.设置(deps\u流:*)
.设置(deps_数据库:*)
.设置(管理的资源:*)
.设置(
序号(
//生成JDOQL实体
编译中的genjdoql:={
生成实体(
sourcepath=(编译中的javaSource).value,
sources=(编译中的非托管源).value,
generated=baseDirectory.value/“target”/scalav(scalaVersion.value)/“src_managed”/“main”/“java”,
classes=(编译中的classDirectory).value,
classpath=(编译中的managedClasspath).value.files,
javacOptions=javacOpts:+“-AqueryMode=PROPERTY”
)},
编译中的SourceGenerator