Question

I'm trying to construct a XML feed, and Groovy's MarkupBuilder is giving me headaches:

 def newsstandFeed(def id) {
    def publication = Publication.get(id)
    def issues = issueService.getActiveIssuesForPublication(publication)
    def updateDate = DateUtil.getRFC3339DateString(publication.lastIssueUpdate)

    def writer = new StringWriter()
    writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
    def xml = new MarkupBuilder(writer)
    xml.feed('xmlns':"http://www.w3.org/2005/Atom", 'xmlns:news':"http://itunes.apple.com/2011/Newsstand") {
        updated("${updateDate}")
        issues.each { issue ->
            entry {
                id (issue.id)
                updated("${DateUtil.getRFC3339DateString(issue.lastUpdated)}")
                published("${DateUtil.getRFC3339DateString(issue.releaseDate)}")
                summary(issue.summary)
                "news:cover_art_icons" {
                    "news:cover_art_icon" (size:"SOURCE", src:"${issue.cover.remotePath}")
                }
            }
        }
    }

    return writer.toString()
}

I get this exception:

Class groovy.lang.MissingMethodException 
No signature of method: java.lang.String.call() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [CYB_001] Possible solutions: wait(), any(), wait(long), any(groovy.lang.Closure), take(int), each(groovy.lang.Closure)

"CYB_001" is the first "id" attribute.

If I rename "id" it to "ids" or anything else, it works, and returns a proper XML document:

            ....
            issues.each { issue ->
            entry {
                ids ("${issue.id}")
                ...

Any ideas why this is happening, and how I can work around the problem?

The environment is Grails 2.1.1 (so Groovy 1.8, I assume)

Was it helpful?

Solution

It seems to me that your XML builder is trying to reference some String variable in the environment. Since groovy builder intercept missing method calls, if they find a reference they will try to apply to it. The following code can reproduce your error:

def id = ""

new groovy.xml.MarkupBuilder().xml {
  id "90"
}

And the following is fine:

def ids = ""

new groovy.xml.MarkupBuilder().xml {
  id "90"
}

Renaming your id variable should do the trick


Update:

An alternative way to use a tag with same name as a variable in the scope is with a (ugly) GString:

def id = ""

new groovy.xml.MarkupBuilder().xml {
  "${'id'}" "90"
}

OTHER TIPS

run into the same situation and qualify it with the builder solved the problem for me.

def writer = new StringWriter()
    def builder = new MarkupBuilder(writer)
    builder.executions() {
        project.scalaVersions.each { scalaVersion ->
            def scalaMajorVer = '_' + scalaVersion.split('\\.')[0..1].join('.')
            def artifactIdStr = publication.artifactId.replaceAll(/_[0-9.]+$/, '') + scalaMajorVer

            execution() {
                builder.id(artifactIdStr) // qualify with builder to avoid collision
                phase('deploy')
                goals() { goal('deploy-file') }
                configuration() {
                    groupId(publication.groupId)
                    artifactId(artifactIdStr)
                    builder.version(project.version) // ditto.
                }
            }
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top