gpt4 book ai didi

java - 即使代码未编译,GroovyClassLoader 对 parseClass 的调用也会成功

转载 作者:行者123 更新时间:2023-12-02 07:27:22 25 4
gpt4 key购买 nike

我正在尝试将 Groovy 脚本作为类动态加载,但即使脚本的代码未编译,也会创建类对象。

例如,我的用于加载 Groovy 脚本的 Groovy 代码的简化版本如下:

GroovyCodeSource src = new GroovyCodeSource(
"blah blah blah",
"Foo.groovy",
GroovyShell.DEFAULT_CODE_BASE
)
new GroovyClassLoader().parseClass(src, true)

显然,代码 blah blah blah 不是合法的 Groovy 脚本。然而,已经成功地为此动态代码创建了一个类对象。根据GroovyClassLoader's Javadoc for the parseClass method对于此类情况,应抛出 CompilationFailedException

怎么可能仍然为损坏的代码创建该类,以及如何根据代码是否可以编译成功地从动态 Groovy 源代码创建一个类?我做了很多研究和实验,但没有结果。

最佳答案

这是因为 groovy 提供了对方法和属性的动态访问,并且就 Groovy 而言,代码 blah blah blah 是有效的。实际上,您正在为脚本提供代码(没有类声明)。编译后,你将得到一个扩展 groovy.lang.Script 的类.

那么,让我继续您的代码并向您展示它如何有效......

GroovyCodeSource src = new GroovyCodeSource(
'blah blah blah',
"Foo.groovy",
GroovyShell.DEFAULT_CODE_BASE
)
def c = new GroovyClassLoader().parseClass(src, true)
println c //class Foo
println c.getSuperclass() //class groovy.lang.Script

def i = c.newInstance()
//i.run() //MissingPropertyException: No such property: blah for class: Foo
i.setBinding([
blah: { x-> return [blah: "x.class =${x.getClass()}"] }
] as Binding)
i.run() //SUCCESS

我还建议您运行groovyconsole,输入blah blah blah,按Ctrl+T,然后检查生成了什么类你的脚本。请注意,您可以在不同的编译/解析阶段之间切换。 enter image description here

<小时/>

一个可能的解决方法是在方法或类上使用 CompileStatic 注释:

//compilation of this code will fail with message
//[Static type checking] - The variable [blah] is undeclared.
@groovy.transform.CompileStatic
def f(){
blah blah blah
}
f()
<小时/>

您可以强制 GroovyClassLoader 对整个脚本进行静态验证。

假设您希望脚本仅访问一些预定义的变量/方法,并且您希望在编译步骤而不是运行时检查这一点。

以下示例展示了如何执行此操作,并且它会在编译期间导致 blah blah blah 代码失败:

import org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder
import org.codehaus.groovy.control.CompilerConfiguration
import groovy.transform.CompileStatic

//your base Script class that declares only valid members
//for example `log`
abstract class MyScript extends groovy.lang.Script{
PrintStream log
}

//create compiler config with base script class
CompilerConfiguration cc = new CompilerConfiguration()
cc.setScriptBaseClass(MyScript.class.getName())
//make static compilation set for class loader
cc = CompilerCustomizationBuilder.withConfig(cc){
ast(CompileStatic)
}
//create classloader with compile config
GroovyClassLoader gcl = new GroovyClassLoader(this.getClass().getClassLoader(),cc)


GroovyCodeSource src = new GroovyCodeSource(
"log.println 'hello world'",
"Foo.groovy",
GroovyShell.DEFAULT_CODE_BASE
)
def c = gcl.parseClass(src, true) //this will fail for 'blah blah blah' source
def i = c.newInstance(log:System.out)
i.run()

附注Groovy 中还有其他可用的代码转换器。

关于java - 即使代码未编译,GroovyClassLoader 对 parseClass 的调用也会成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57897628/

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