Impossibility to iterate over a Map using Groovy within Jenkins Pipeline

爱⌒轻易说出口 提交于 2019-11-29 11:51:11

问题


We are trying to iterate over a Map, but without any success. We reduced our issue to this minimal example:

def map = [
           'monday': 'mon',
           'tuesday': 'tue',
           ]

If we try to iterate with:

map.each{ k, v -> println "${k}:${v}" }

Only the first entry is output: monday:mon


The alternatives we know of are not even able to enter the loop:

for (e in map)
{
    println "key = ${e.key}, value = ${e.value}"
}

or

for (Map.Entry<String, String> e: map.entrySet())
{
    println "key = ${e.key}, value = ${e.value}"
}

Are failing, both only showing the exception java.io.NotSerializableException: java.util.LinkedHashMap$Entry. (which could be related to an exception occurring while raising the 'real' exception, preventing us from knowing what happened).

We are using latest stable jenkins (2.19.1) with all plugins up-to-date as of today (2016/10/20).

Is there a solution to iterate over elements in a Map within a Jenkins pipeline Groovy script ?


回答1:


Its been some time since I played with this, but the best way to iterate through maps (and other containers) was with "classical" for loops, or the "for in". See Bug: Mishandling of binary methods accepting Closure

To your specific problem, most (all?) pipeline DSL commands will add a sequence point, with that I mean its possible to save the state of the pipeline and resume it at a later time. Think of waiting for user input for example, you want to keep this state even through a restart. The result is that every live instance has to be serialized - but the standard Map iterator is unfortunately not serializable. Original Thread

The best solution I can come up with is defining a Function to convert a Map into a list of serializable MapEntries. The function is not using any pipeline steps, so nothing has to be serializable within it.

@NonCPS
def mapToList(depmap) {
    def dlist = []
    for (def entry2 in depmap) {
        dlist.add(new java.util.AbstractMap.SimpleImmutableEntry(entry2.key, entry2.value))
    }
    dlist
}

This has to be obviously called for each map you want to iterate, but the upside it, that the body of the loop stays the same.

for (def e in mapToList(map))
{
    println "key = ${e.key}, value = ${e.value}"
}

You will have to approve the SimpleImmutableEntry constructor the first time, or quite possibly you could work around that by placing the mapToList function in the workflow library.




回答2:


Or much simpler

for (def key in map.keySet()) {
  println "key = ${key}, value = ${map[key]}"
}


来源:https://stackoverflow.com/questions/40159258/impossibility-to-iterate-over-a-map-using-groovy-within-jenkins-pipeline

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!