尝试在Groovy中使用属性访问时遇到问题。参加以下课程:
class Foo {
Map m = [:]
String bar
void getProperty(String name) {
m.get name
}
def setProperty(String name, value) {
m.set name, value
}
String getBarString() {
return bar // local access, does not go through getProperty()
}
}
它会覆盖getter和setter,只是将值放入Map而不是对象的普通属性空间。在摘要中,这有点愚蠢,但想象一下,不是将数据放入地图,而是将数据保存到数据库或其他有用的地方。
不幸的是,以下代码现在不起作用:
foo = new Foo()
foo.bar = "blerg" // using foo.bar invokes the setProperty interceptor
assert foo.bar == "blerg" // this will work fine as foo.bar here uses the getProperty interceptor
assert foo.getBarString() == "blerg" // explosion and fire! getBarString accesses bar locally without going through the getProperty interceptor so null will actually be returned.
当然有解决方法,setProperty可以同时设置MetaProperty和Map值等。但是,我想到的所有策略都需要程序员多加注意,以确保他们正在访问类属性的确切方式。
此外,Groovy中的一些内置很棒的东西(例如@Delegate)使用直接的MetaProperty访问而不是通过getProperty,因此以下内容永远不会起作用:
class Meep {
String getMyMeep() {
return "MEEP!!!"
}
}
class Foo {
Map m = [:]
String bar
@Delegate Meep meep
void getProperty(String name) {
m.get name
}
def setProperty(String name, value) {
m.set name, value
}
String getBarString() {
return bar
}
}
foo = new Foo()
foo.meep = new Meep() // uses setProperty and so does not place the Meep in the Map m
foo.getMyMeep()
在最后一行抛出空指针异常,因为@Delegate使用MetaProperty直接访问(实际上是this.meep.getMyMeep()而不是getProperty拦截器。不幸的是'meep'为null,尽管getProperty('meep')会不是。
总之,我正在寻找的是一种解决以下标准的策略:
提前致谢!
答案 0 :(得分:1)
您可以使用
foo.@meep = new Meep()
为了绕过setProperty
方法直接访问属性。
尽管foo.meep
仍会触发set/getProperty
,但这并不能完全解决您的问题。
你可以采用的另一种方法是直接使用会面的getter和setter,即
foo.setMeep(new Meep())
因此,一种统一的方法是将所有变量定义为私有并使用get / set * PropertyName *
答案 1 :(得分:1)
通过使用AST转换,我可以执行以下操作:
为每个重命名的字段添加一个getter / setter,如下所示
def get_ x _(){ <强> X 强> }
...以 x 作为字段而不是Groovy属性进行访问 - 现在在以下类中应用转换
class Foo {
def x
def y
Map m = [:]
@Delegate Date date // for testing if non-local fields work
def getProperty(String name) {
if (this.respondsTo("get__${name}__")) // if this is one of our custom fields
return "get__${name}__"()
"get${Verifier.capitalize(name)}"() // pass to specific getter method
}
void setProperty {
if (this.respondsTo("set__${name}__")) {
"set__${name}__"(value)
m[name] = value
if (name == "x") y = x + 1
return
}
"set${Verifier.capitalize(name)}"(value)
}
}
现在运行这样的测试方法:
public void testAST(){ def file = new File('。/ src / groovy / TestExample.groovy') GroovyClassLoader调用者=新的GroovyClassLoader() def clazz = invoker.parseClass(file) def out = clazz.newInstance()
out.x = 10 断言out.y == 11 out.y = 5 断言out.y == 5 out.x = 2 断言out.m.containsKey('x') 断言out.m.x == 2 断言out.m.y == 3
out.date = new Date() 断言out.time&amp;&amp; out.time&gt; 0 }
一切都应该成功,包括获得更新,正确访问日期委托方法时间等等。
-Glenn