Inability to iterate over a map using Groovy in a Jenkins pipeline

We are trying to iterate over Map , but without any success. We reduced our problem 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 monday:mon


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

 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}" } 

Failed, both indicated only java.io.NotSerializableException: java.util.LinkedHashMap$Entry exception java.io.NotSerializableException: java.util.LinkedHashMap$Entry . (which may be due to an exception that occurs when raising a "real" exception, not allowing us to find out what happened).

We use the latest stable jenkins (2.19.1) with all the plugins that are relevant to date (2016/10/20).

Is there a solution for iterating over elements in a Map in the Jenkins Groovy script pipeline?

+11
dictionary jenkins groovy jenkins-pipeline
source share
2 answers

It has been a while since I played with this, but the best way to iterate over maps (and other containers) was with the "classic" for loops or for. See Error: misuse of binary methods accepting closure

Most (all?) DSL pipeline commands will add a sequence point to your specific problem, and I mean its ability to save the state of the pipeline and resume it later. For example, think about waiting for user input, you want to save this state even after a restart. As a result, each live instance must be serialized, but the standard map iterator, unfortunately, is not serializable. Original theme

The best solution I can come up with is to define a function to convert the Map to a list of serializable MapEntries. The function does not use any pipeline steps, so there is no need to serialize 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 should obviously be called for every card you want to iterate over, but at the top so that the body of the loop remains the same.

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

You will need to approve the SimpleImmutableEntry constructor for the first time, or, quite possibly, you can get around this by placing the mapToList function in the workflow library.

+19
source share

Or much easier

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

All Articles