Groovy的MarkupBuilder名称冲突

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”标签...我已经尝试了世界上的所有方法来让该节点出现。我快要抓狂了!谢谢您提前帮助。
1个回答

12

可能有更好的方法,但一个技巧是直接调用invokeMethod

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.identityowner.identity起作用,这些通常是使用的技巧。


编辑:我找到了问题出在哪里。

Groovy向每个对象添加了一个签名为identity(Closure c)的方法

这意味着当你试图在XML构建器上动态调用identity元素并传入单个闭包参数时,它会调用identity()方法,这就像在外部闭包上调用delegate({...})一样。

使用 invokeMethod 技巧强制 Groovy 绕过元对象协议并将该方法视为动态方法,即使 identity 方法已经存在于 MetaObject 上也可以。

了解了这点,我们可以组合出更好、更易读的解决方案。我们只需改变方法的签名即可:

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();
}

这种写法更易读,意图更明确,并且注释(希望如此)可以防止任何人删除“不必要”的空映射。


可以解释一下吗?那个方法可行,但是什么是委托(delegate),为什么delegate.identity和delegate.invokeMethod('identity')不同呢? - James Watkins
FYI:我使用 GroovyConsole 检查 XML 对象来追踪此问题。这让我知道 identity 方法已经存在,并且它只有一个 Closure 作为参数。 - OverZealous
当我使用“版本”和“描述”字段时,遇到了同样的问题,幸运的是,在Github上搜索后,我找到了参考这个答案! - Hsilgos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接