Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-61169

Non-Serializable exception thrown on wrong object

XMLWordPrintable

      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.

            pskumar448 Suresh Kumar
            eggmatters Matthew Eggers
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: