0

以下は、getXXXのオブジェクトのすべてのメソッドを動的に呼び出すプログラムです。-name はコマンドライン経由で渡されます。そして、それはうまく機能します。CLASSCLASS

// 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
4

1 に答える 1

2

これは、リフレクション ベースのもの ( x.class.methods.each1 つ) を使用すると、GString の評価時にコードを連結して生成し、現在のスコープに対して 1 つの変数のみを解決するために発生しますarg。コードを印刷すると、完全に実行可能な Groovy コードが出力されます。

x = new Date()
x.class.methods.each { f ->
    if (f.name.startsWith("get")) {
        print "new Date()." + f.name + ": " + f.invoke(x) 
        println ''
    }
}  

2 番目のバージョンでは、GString変数は作成されたスコープ (スクリプト バインディング) に対して解決されます。fしたがって、変数からではなく、そのスコープから変数をフェッチしようとしcodeます。そしてそれが${f}変数でクラッシュする理由です。

code変数を単純な文字列 (一重引用符) に変更すると、変数が解決されないため、変数argを少し調整して新しいクラスを作成する必要があります。それでも、groovy callAllMethods java.util.Dategroovy ではない (しゃれが意図された) 引数として渡さない限り、失敗します。

したがって、コードをそのように使用するには、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ただし、 :-)にはもう少し多くのものを出力します。

于 2013-06-02T13:42:05.590 に答える