gpt4 book ai didi

grails - 如何在 Grails 插件中实现 Groovy 全局 AST 转换?

转载 作者:行者123 更新时间:2023-12-01 11:36:00 25 4
gpt4 key购买 nike

我想在编译时修改我的一些 Grails 域类。我最初认为这是 Groovy 的全局 ASTTransformation 的工作,因为我不想注释我的域类(它本地变压器需要)。执行此操作的最佳方法是什么?

我还尝试通过在同一个包中创建自己的类、实现相同的接口(interface)来模仿 DefaultGrailsDomainClassInjector.java,但我可能只是不知道如何将它打包到正确的位置,因为我从未见过我的方法被调用。

另一方面,我能够手动创建一个 JAR,其中包含一个已编译的 AST 转换类,以及普通 Groovy 全局转换所需的 META-INF/服务工件。我将该 JAR 放入我项目的“lib”目录中,并成功调用了 visit()。显然这是一项草率的工作,因为我希望在 Grails 插件中拥有我的 AST 转换的源代码,如果不需要的话不需要单独的 JAR 工件,而且我无法通过拥有这种方法来工作JAR 在我的 Grails 插件的“lib”中,但不得不将它放入 Grails 应用程序的“lib”中。

这篇文章也有点帮助:Grails 2.1.1 - How to develop a plugin with an AstTransformer?

最佳答案

关于全局转换的事情,转换代码应该在编译开始时可用。把变压器放在 jar 里是我首先做的!但正如你所说,这是一项草率的工作。你想要做的是在其他人进入编译阶段之前编译你的 ast 转换类。这就是您要做的!

准备变压器

src 文件夹中创建一个名为 precompiled 的目录!并在该目录下以正确的封装结构添加Transformation类和transformer使用的类(如注解)。

然后在名为 precompiled/META-INF/services 中创建一个名为 org.codehaus.groovy.transform.ASTTransformation 的文件,您将具有以下结构。

precompiled
--amanu
----LoggingASTTransformation.groovy
--META-INF
----services
------org.codehaus.groovy.transform.ASTTransformation

然后在 org.codehaus.groovy.transform.ASTTransformation 文件中写入转换器的完全限定名称,对于上面的示例,完全限定名称将是 amanu.LoggingASTTransformation

实现

package amanu 

import org.codehaus.groovy.transform.GroovyASTTransformation
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.control.SourceUnit

@GroovyASTTransformation(phase=CompilePhase.CANONICALIZATION)
class TeamDomainASTTransformation implements ASTTransformation{

public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
println ("*********************** VISIT ************")
source.getAST()?.getClasses()?.each { classNode ->
//Class node is a class that is contained in the file being compiled
classNode.addProperty("filed", ClassNode.ACC_PUBLIC, new ClassNode(Class.forName("java.lang.String")), null, null, null)
}
}
}

编译

执行此操作后,您可以通过两种方式开始!第一种方法是把它放在 jar 里,就像你做的那样!另一种是使用groovy脚本先于别人编译。要在 grails 中执行此操作,我们使用 _Events.groovy 脚本。

您可以从插件或主项目中执行此操作,这并不重要。如果它不存在,创建一个名为 _Events.groovy 的文件并添加以下内容。

代码复制自reinhard-seiler.blogspot.com有修改

eventCompileStart = {target ->  
...
compileAST(pluginBasedir, classesDirPath)
...
}
def compileAST(def srcBaseDir, def destDir) {
ant.sequential {
echo "Precompiling AST Transformations ..."
echo "src ${srcBaseDir} ${destDir}"
path id: "grails.compile.classpath", compileClasspath
def classpathId = "grails.compile.classpath"
mkdir dir: destDir
groovyc(destdir: destDir,
srcDir: "$srcBaseDir/src/precompiled",
classpathref: classpathId,
stacktrace: "yes",
encoding: "UTF-8")
copy(toDir:"$destDir/META-INF"){
fileset(dir:"$srcBaseDir/src/precompiled/META-INF")
}
echo "done precompiling AST Transformations"
}
}

前面的脚本会在其他脚本编译之前编译转换器!这使转换器可用于转换您的域类。

不要忘记

如果您使用除添加到您的类路径中的类之外的任何类,您也必须预编译这些类。上面的脚本将编译 precompiled 目录中的所有内容,您还可以在该目录中添加不需要 ast 但需要它的类!

如果你想在转换中使用域类,你可能想在 evenCompileEnd block 中进行预编译!但这会使事情变得更慢!

更新

@Douglas Mendes 提到有一种简单的方法可以引起预编译。哪个更简洁。

eventCompileStart = { 
target -> projectCompiler.srcDirectories.add(0, "./src/precompiled")
}

关于grails - 如何在 Grails 插件中实现 Groovy 全局 AST 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27115294/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com