没有 resolveStrategy=DELEGATE_FIRST 属性最终成为绑定变量
without resolveStrategy=DELEGATE_FIRST properties end up as binding variables
我正在尝试编写可以从 Groovy 配置文件加载的 java bean。配置格式需要闭包中的属性,如果我不调用 c.setResolveStrategy(Closure.DELEGATE_FIRST)
,那么闭包内设置的所有属性最终都会作为绑定变量。我的程序输出:
In closure
confpojo.myTestProp: null
binding.myTestProp: true
confpojo.app.myOther.myTestSubProp: null
binding.myTestSubProp: true
在这个答案中 他们没有更改默认的 resolveStrategy,它似乎有效。有什么不同? configaaa.groovy
:
app {
println 'In closure'
myTestProp = true
myOther {
myTestSubProp = true
}
}
_
public abstract class AaaTestGroovyConfig extends Script {
public static class App {
public void myOther(final Closure c) {
c.setDelegate(myOther);
// c.setResolveStrategy(Closure.DELEGATE_FIRST);
c.call();
}
private Boolean myTestProp;
private final Other myOther = new Other();
public Boolean getMyTestProp() {
return myTestProp;
}
public void setMyTestProp(final Boolean active) {
this.myTestProp = active;
}
}
public void app(final Closure c) {
c.setDelegate(app);
// c.setResolveStrategy(Closure.DELEGATE_FIRST);
c.call();
}
private App app = new App();
public static void main(final String[] args) throws Exception {
final CompilerConfiguration cc = new CompilerConfiguration();
cc.setScriptBaseClass(AaaTestGroovyConfig.class.getName());
// final ClassLoader cl = AaaTestGroovyConfig.class.getClassLoader();
final Binding binding = new Binding();
final GroovyShell shell = new GroovyShell(binding, cc);
final Script script = shell.parse(new File("configaaa.groovy"));
final AaaTestGroovyConfig confpojo = (AaaTestGroovyConfig) script;
// ((DelegatingScript) script).setDelegate(confpojo);
script.run();
System.out.println("confpojo.myTestProp: " + confpojo.app.myTestProp);
printBindingVar(binding, "myTestProp");
System.out
.println("confpojo.app.myOther.myTestSubProp: " + confpojo.app.myOther.myTestSubProp);
printBindingVar(binding, "myTestSubProp");
}
private static void printBindingVar(final Binding binding, final String name) {
System.out
.println(
"binding." + name + ": " + (binding.hasVariable(name)
? binding.getVariable(name)
: ""));
}
public static class Other {
private Boolean myTestSubProp;
public Boolean getMyTestSubProp() {
return myTestSubProp;
}
public void setMyTestSubProp(final Boolean myTestSubProp) {
this.myTestSubProp = myTestSubProp;
}
}
public App getApp() {
return app;
}
public void setApp(final App app) {
this.app = app;
}
}
因为默认值为OWNER_FIRST
https://docs.groovy-lang.org/latest/html/api/groovy/lang/Closure.html#OWNER_FIRST
并且您有 2 级关闭,所以 - 所有者对他们来说是不同的
尝试这样的事情,你会看到不同
app {
println "delegate=$delegate owner=${owner.getClass()}"
myOther {
println "delegate=$delegate owner=${owner.getClass()}"
}
}
PS:让我建议你让你的代码更优雅:
//generic config class
class MyConf {
private HashMap objMap
static def build(HashMap<String,Class> classMap, Closure builder){
MyConf cfg = new MyConf()
cfg.objMap = classMap.collectEntries{ k,cl-> [k, cl.newInstance()] }
cfg.objMap.each{ k,obj->
//define method with name `k` and with optional closure parameter
cfg.metaClass[k] = {Closure c=null ->
if(c) {
// call init closure with preset delegate and owner
return c.rehydrate(/*delegate*/ obj, /*owner*/cfg, /*this*/cfg).call()
}
return obj //return object itself if no closure
}
}
cfg.with(builder) // call root builder closure with cfg as a delegate
return cfg
}
}
//bean 1
@groovy.transform.ToString
class A{
int id
String name
}
//bean 2
@groovy.transform.ToString
class B{
int id
String txt
}
//beans init
def cfg = MyConf.build(app:A.class, other:B.class){
app {
id = 123
name = "hello 123"
other {
id = 456
txt = "bye 456"
}
}
}
//get initialized beans
println cfg.app()
println cfg.other()
我正在尝试编写可以从 Groovy 配置文件加载的 java bean。配置格式需要闭包中的属性,如果我不调用 c.setResolveStrategy(Closure.DELEGATE_FIRST)
,那么闭包内设置的所有属性最终都会作为绑定变量。我的程序输出:
In closure
confpojo.myTestProp: null
binding.myTestProp: true
confpojo.app.myOther.myTestSubProp: null
binding.myTestSubProp: true
在这个答案中 他们没有更改默认的 resolveStrategy,它似乎有效。有什么不同? configaaa.groovy
:
app {
println 'In closure'
myTestProp = true
myOther {
myTestSubProp = true
}
}
_
public abstract class AaaTestGroovyConfig extends Script {
public static class App {
public void myOther(final Closure c) {
c.setDelegate(myOther);
// c.setResolveStrategy(Closure.DELEGATE_FIRST);
c.call();
}
private Boolean myTestProp;
private final Other myOther = new Other();
public Boolean getMyTestProp() {
return myTestProp;
}
public void setMyTestProp(final Boolean active) {
this.myTestProp = active;
}
}
public void app(final Closure c) {
c.setDelegate(app);
// c.setResolveStrategy(Closure.DELEGATE_FIRST);
c.call();
}
private App app = new App();
public static void main(final String[] args) throws Exception {
final CompilerConfiguration cc = new CompilerConfiguration();
cc.setScriptBaseClass(AaaTestGroovyConfig.class.getName());
// final ClassLoader cl = AaaTestGroovyConfig.class.getClassLoader();
final Binding binding = new Binding();
final GroovyShell shell = new GroovyShell(binding, cc);
final Script script = shell.parse(new File("configaaa.groovy"));
final AaaTestGroovyConfig confpojo = (AaaTestGroovyConfig) script;
// ((DelegatingScript) script).setDelegate(confpojo);
script.run();
System.out.println("confpojo.myTestProp: " + confpojo.app.myTestProp);
printBindingVar(binding, "myTestProp");
System.out
.println("confpojo.app.myOther.myTestSubProp: " + confpojo.app.myOther.myTestSubProp);
printBindingVar(binding, "myTestSubProp");
}
private static void printBindingVar(final Binding binding, final String name) {
System.out
.println(
"binding." + name + ": " + (binding.hasVariable(name)
? binding.getVariable(name)
: ""));
}
public static class Other {
private Boolean myTestSubProp;
public Boolean getMyTestSubProp() {
return myTestSubProp;
}
public void setMyTestSubProp(final Boolean myTestSubProp) {
this.myTestSubProp = myTestSubProp;
}
}
public App getApp() {
return app;
}
public void setApp(final App app) {
this.app = app;
}
}
因为默认值为OWNER_FIRST
https://docs.groovy-lang.org/latest/html/api/groovy/lang/Closure.html#OWNER_FIRST
并且您有 2 级关闭,所以 - 所有者对他们来说是不同的
尝试这样的事情,你会看到不同
app {
println "delegate=$delegate owner=${owner.getClass()}"
myOther {
println "delegate=$delegate owner=${owner.getClass()}"
}
}
PS:让我建议你让你的代码更优雅:
//generic config class
class MyConf {
private HashMap objMap
static def build(HashMap<String,Class> classMap, Closure builder){
MyConf cfg = new MyConf()
cfg.objMap = classMap.collectEntries{ k,cl-> [k, cl.newInstance()] }
cfg.objMap.each{ k,obj->
//define method with name `k` and with optional closure parameter
cfg.metaClass[k] = {Closure c=null ->
if(c) {
// call init closure with preset delegate and owner
return c.rehydrate(/*delegate*/ obj, /*owner*/cfg, /*this*/cfg).call()
}
return obj //return object itself if no closure
}
}
cfg.with(builder) // call root builder closure with cfg as a delegate
return cfg
}
}
//bean 1
@groovy.transform.ToString
class A{
int id
String name
}
//bean 2
@groovy.transform.ToString
class B{
int id
String txt
}
//beans init
def cfg = MyConf.build(app:A.class, other:B.class){
app {
id = 123
name = "hello 123"
other {
id = 456
txt = "bye 456"
}
}
}
//get initialized beans
println cfg.app()
println cfg.other()