'Why this error? "No such property: Entry for class: java.util.Map"

I'm following an example from JENKINS-44085 issue very-bottom comments about creating a stage map almost to the T, but when I execute my code I get

No such property: Entry for class: java.util.Map

Here's my code. Variable 'pipeline' is defined somewhere else, and is valid.

def generateStage(String job, String targetVersion,
                  String rootVersion, Integer sleepTime=0) {
    return {
        stage("Deploying: ${job}") {
              sleep sleepTime
              pipeline.executeDeploymentPipeline(job,
                                                 targetVersion,
                                                 rootVersion)
        }
    }
}

def deployProcs(targetVersion, rootVersion) {
    int sleepTime = 0
    def procs = ["proc-proc", "proc-proc-high"]
    def parallelStagesMap = procs.collectEntries {
        ["${it}" : generateStage(it, targetVersion, rootVersion, sleepTime)]
        sleepTime += 5
    }
    parallel parallelStagesMap
}

Why is that?



Solution 1:[1]

It seems this is a bug in Jenkins pipelines. A related one was fixed after version 2.158. So upgrading Jenkins should resolve this.

Solution 2:[2]

Unlike what @Christian pointed out, this is still a bug as of 1.176.1 with all plugins up to date. The workaround is to convert the map entries into a [key, value] list pair. To demonstrate, here is a simple code that can reproduce the OP's error:

['1':1].findAll { it.value > 0 }.collectEntries { it }

Here is the one with the workaround,

['1':1].collect { [it.key, it.value] }.findAll { it[1] > 0 }.collectEntries { it }

Note that .collectEntries() works with list pairs just fine, so no need to convert it back to any other form.

Solution 3:[3]

Not a direct answer, but I did this as a workaround, for the calling function.

def deployProcs(targetVersion, rootVersion) {
    int sleepTime = 0
    def procs = ["proc-proc", "proc-proc-high"]
    Map parallelStagesMap = new TreeMap()
    procs.each {
        parallelStagesMap.put[it, generateStage(it, targetVersion, rootVersion, sleepTime))
        sleepTime += 5
    }
    parallel parallelStagesMap
}

Still bothers me why the original code does not work.

Solution 4:[4]

I had the same problem. The solution proposed by @haridsv also works if you want to modify the map based on some conditions and return this modified map:

def b = [a: 'buba', b: 'cuba', c: 'cuda']

def s = true

def c = b
   .collect { s ? [it.key, it.value -= 'c'] : it }
   .collectEntries { it }

println c

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Christian
Solution 2
Solution 3 Chris F
Solution 4 Adam Bogdan Boczek