以下是一个程序,它动态调用getXXX
对象上的所有CLASS
方法,其中CLASS
- 名称通过命令行传递。 它运作得很好。
// Program: callAllMethods.groovy
// Invoke this program as: groovy callAllMethods Date
args.each { arg ->
println "Methods of ${arg} ..."
def code = """
x = new ${arg}()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
print "new ${arg}()." + f.name + ": " + f.invoke(x)
println ''
}
}
"""
evaluate("$code")
println ''
}
然而,当我尝试更简单的动态方法调用方式(不使用METHOD.invoke(OBJECT)
而是使用OBJECT."METHOD-NAME"()
)时,就像这样,
// Program: callAllMethods.groovy
// Invoke this program as: groovy callAllMethods Date
args.each { arg ->
println "Methods of ${arg} ..."
def code = """
x = new ${arg}()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
result = x."${f.name}"()
println "new ${arg}().${f.name}: ${result}"
}
}
"""
evaluate("$code")
println ''
}
...我收到以下错误:
$ groovy callGetMethods.groovy Date
Methods of Date ...
Caught: groovy.lang.MissingPropertyException: No such property: f for class: callGetMethods
groovy.lang.MissingPropertyException: No such property: f for class: callGetMethods
at callGetMethods$_run_closure1.doCall(callGetMethods.groovy:13)
at callGetMethods.run(callGetMethods.groovy:10)
我无法理解为什么!我正在使用的Groovy版本:
$ groovy -version
Groovy Version: 2.1.3 JVM: 1.6.0_43 Vendor: Sun Microsystems Inc. OS: Linux
答案 0 :(得分:2)
之所以会发生这种情况,是因为当你使用基于反射的(x.class.methods.each
一个)时,你会连接并在GString评估时生成代码,它只针对当前范围解析一个变量,即arg
,那没关系。如果您打印代码,它会输出一个完全可运行的Groovy代码:
x = new Date()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
print "new Date()." + f.name + ": " + f.invoke(x)
println ''
}
}
在第二个版本中,GString
变量将根据它们创建的范围进行解析,即脚本绑定。因此它尝试从该范围中获取f
变量,而不是从code
变量中获取。这就是它在${f}
变量崩溃的原因。
如果您将code
变量更改为普通字符串(单引号),它将无法解析变量arg
,因此您需要对其进行一些调整以创建新变量从它上课。即便如此,它也会失败,除非你作为参数groovy callAllMethods java.util.Date
传递,这不是常规(双关语)。
因此,要以这种方式使用您的代码,GString不应该在声明时间内解析,而是在evaluate()
时间解析。仍然,arg
变量需要在声明时间内解析,因此,您需要连接它。结果如下:
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.class.methods.each { m ->
if (m.name.startsWith("get")) {
result = x."${m.name}"()
println "new '''+arg+'''().${m.name}: ${result}"
}
}
'''
evaluate code
println ''
}
其中,在我的方框(jdk7,groovy 2.1.3)中,输出:
new Date().getDay: 0
new Date().getTimezoneOffset: 180
new Date().getDate: 2
new Date().getHours: 10
new Date().getMinutes: 39
new Date().getMonth: 5
new Date().getSeconds: 56
new Date().getTime: 1370180396136
new Date().getYear: 113
new Date().getClass: class java.util.Date
如果您只想从对象输出属性,我可以建议object.properties
吗?
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.properties.each {
println "new '''+arg+'''().${it.key}: ${x[it.key]}"
}
'''
evaluate code
println ''
}
它为Date
输出了更多东西,但是: - )。