- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将 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,然后检查生成了什么类你的脚本。请注意,您可以在不同的编译/解析阶段之间切换。
一个可能的解决方法是在方法或类上使用 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/
当使用GroovyClassLoader时,什么时候应该使用loadClass,什么时候应该调用parseClass? 如果我理解,第一次调用 loadClass() 将编译脚本,后续调用将使用缓存的
我正在尝试将 Groovy 脚本作为类动态加载,但即使脚本的代码未编译,也会创建类对象。 例如,我的用于加载 Groovy 脚本的 Groovy 代码的简化版本如下: GroovyCodeSource
我是一名优秀的程序员,十分优秀!