5

私はこのコードを持っています:

String buildCatalog(Catalog catalog) {
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
        'identity'() {
            groupId(catalog.groupId)
            artifactId(catalog.artifactId)
            version(catalog.version)
        }
    }

    return writer.toString();
}

このxmlを生成します:

<catalog xmlns='http://www.sybrium.com/XMLSchema/NodeCatalog'>
  <groupId>sample.group</groupId>
  <artifactId>sample-artifact</artifactId>
  <version>1.0.0</version>
</catalog>

「identity」タグが欠落していることに注意してください...私はそのノードを表示するために世界中ですべてを試しました。髪を引き裂きます!

前もって感謝します。

4

1 に答える 1

12

invokeMethodより良い方法があるかもしれませんが、1つのトリックは直接呼び出すことです:

String buildCatalog(Catalog catalog) {
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
        delegate.invokeMethod('identity', [{
            groupId(catalog.groupId)
            artifactId(catalog.artifactId)
            version(catalog.version)
        }])
    }

    return writer.toString();
}

これは事実上、Groovyが舞台裏で行っていることです。いつものトリックである、私は得ることも働くdelegate.identityこともできませんでした。owner.identity


編集:私は何が起こっているのか理解しました。

Groovyは、すべてのオブジェクトに署名付きのメソッドを追加します。identity(Closure c)

identityこれは、単一のクロージャ引数を渡しながらXMLビルダーで要素を動的に呼び出そうとしたときに、外部クロージャidentity()を呼び出すのと同じようにメソッドを呼び出していたことを意味します。delegate({...})

このinvokeMethodトリックを使用すると、Groovyはメタオブジェクトプロトコルをバイパスし、メソッドがメタオブジェクトにidentityすでに存在している場合でも、そのメソッドを動的メソッドとして扱います。

これを知っていると、より良い、より読みやすいソリューションをまとめることができます。次のように、メソッドのシグネチャを変更するだけです。

String buildCatalog(Catalog catalog) {
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
        // NOTE: LEAVE the empty map here to prevent calling the identity method!
        identity([:]) {
            groupId(catalog.groupId)
            artifactId(catalog.artifactId)
            version(catalog.version)
        }
    }

    return writer.toString();
}

これははるかに読みやすく、意図がより明確であり、コメントは(うまくいけば)誰かが「不要な」空のマップを削除するのを防ぐはずです。

于 2012-07-09T04:20:14.110 に答える