简体   繁体   English

Groovy MarkupBuilder名称冲突

[英]Groovy MarkupBuilder name conflict

I have this code: 我有这个代码:

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

It produces this xml: 它产生这个xml:

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

Notice that the "identity" tag is missing... I've tried everything in the world to get that node to appear. 请注意,“身份”标签丢失了...我已经尝试了世界上的所有内容来显示该节点。 I'm ripping my hair out! 我正在撕开我的头发!

Thanks in advance. 提前致谢。

There might be a better way, but one trick is to call invokeMethod directly: 可能有更好的方法,但一个技巧是直接调用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();
}

This is effectively what Groovy is doing behind the scenes. 这实际上是Groovy在幕后所做的事情。 I couldn't get delegate.identity or owner.identity to work, which are the usual tricks. 我无法让delegate.identityowner.identity工作,这是常用的技巧。


Edit : I figured out what's going on. 编辑 :我弄清楚发生了什么。

Groovy adds a method with a signature of identity(Closure c) to every object. Groovy为每个对象添加了一个带有identity(Closure c)签名identity(Closure c)方法。

This means that when you tried to dynamically invoke the identity element on the XML builder, while passing in a single closure argument, it was calling the identity() method, which is like calling delegate({...}) on the outer closure. 这意味着当您尝试动态调用XML构建器上的identity元素时,在传入单个闭包参数时,它调用了identity()方法,就像在外部闭包上调用delegate({...})

Using the invokeMethod trick forces Groovy to bypass the Meta Object Protocol and treat the method as a dynamic method, even though the identity method already exists on the MetaObject. 使用invokeMethod技巧强制Groovy绕过元对象协议并将该方法视为动态方法,即使MetaObject上已存在identity方法。

Knowing this, we can put together a better, more legible solution. 了解这一点,我们可以将更好,更清晰的解决方案整合在一起。 All we have to do is change the signature of the method, like so: 我们所要做的就是更改方法的签名,如下所示:

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

This is much more readable, it's clearer the intent, and the comment should (hopefully) prevent anyone from removing the "unnecessary" empty map. 这更具可读性,意图更清晰,评论应该(希望)阻止任何人删除“不必要的”空地图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM