-
Bug
-
Resolution: Unresolved
-
Major
-
None
-
Jenkins 2.164.1
pipelines-groovy plugin
I am getting an exception when attempting to serialize a groovy Map that I've generated:
an exception which occurred: in field groovy.lang.Closure.delegate in object Script1$_run_closure1@30d6aac5 in field com.pipeline.configuration.adaptors.AdvancedClientAdaptor.clientConverter in object com.pipeline.configuration.adaptors.AdvancedClientAdaptor@629f71ba in field com.cloudbees.groovy.cps.impl.BlockScopeEnv.locals in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@2c17fa09 in field com.cloudbees.groovy.cps.impl.CallEnv.caller in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@1635b321 in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@146f27c2 in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@19d1436 in field com.cloudbees.groovy.cps.impl.CallEnv.caller in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@1d8bbdc9 in field com.cloudbees.groovy.cps.Continuable.e in object org.jenkinsci.plugins.workflow.cps.SandboxContinuable@39c61bdb in field org.jenkinsci.plugins.workflow.cps.CpsThread.program in object org.jenkinsci.plugins.workflow.cps.CpsThread@7ebbe670 in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.threads in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@3b2aa9f8 in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@3b2aa9f8 Caused: java.io.NotSerializableException: Script1
The problem here is, I'm not asking AdvancedClientAdaptor to persist the clientConverter field (It has Closures in it). I'm asking it to persist a JsonStringified groovy map.
The issue appears to be in the AdvanceClientAdaptor class I've written. It accepts groovy map that it performs transformations on. Here is a trivial example:
def Map = [ targetConfig: [ foo: "bar" ], clientConverter: [ foo: { targetConfig, value -> targetConfig['foo'] = value }] ]
The AdvancedClientConverter class basically accepts this Map as an input, assigns 2 member property variables to each of the 2 map fields above:
class AdvancedClientConverter implements Serializable { Map targetConfig Map clientConverter def steps //running groovy instance AdvancedClientConverter(Map converterMap, def steps) { this.clientConverter = converterMap.clientConverter this.targetConfig = converterMap.targetConfig this.steps = steps } def converterOperation() { this.targetConfig.foo = this.clientConverter.foo(this.targetConfig, "baz"); String fileString = JsonOutput.prettyPrint(JsonOutput.toJson(targetConfig))} steps.echo ("final config: ${fileString}") steps.writeFile file: "FinalConfig.text", text: fileString return target } }
The above is all invoked in a running Jenkins Pipeline:
#!groovy @Library(['pipeline-library-with-advanced-client-adaptor']) _ def config = [] def converterMap = //converter map listed above node { def advancedClientAdaptor = new AdvancedClientAdaptor(this, converterMap) //Failure: advancedClientAdaptor.converterOperation() }
This will throw the above exception. The actual object persisted however, looks accurate. The echo step prior to the writeFile call produces:
{ "foo": "baz" }
Yet the exception is thrown on a Completely different field that I am not persisting
Even though, those values entered this class as part of the same map, they are assigned as separate member variables and presumably, different memory addresses.
The String being persisted appears sanitary (No closures or other Non-serializable entities)
This does not occur in JVM (Java 11) running Groovy 2.5.8 performing File.write commands.
The writeFile operation succeeds if using the @NonCPS annotation (but @NonCPS breaks other functionality of the class)
Please let me know if you need additional details or a working sample app that reproduces this issue.