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

JsonSlurper does not work after updating to Jenkins 2.x

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: Minor Minor
    • script-security-plugin
    • None
    • Jenkins 2.6, pipeline 2.1, script-security 1.19

      After installing jenkins 2.6 locally to test my pipeline scripts, I am unable to use JsonSlurper due to errors about LazyMap not being serializable.

      java.io.NotSerializableException: groovy.json.internal.LazyMap
      

      That can't be changed so I looked for a workaround and tried passing the LazyMap into the constructor of a new HashMap:

      org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.util.HashMap java.util.Map
      

      So then I found the JsonSlurperClassic class, which should solve the issue by going back to the Groovy 1.x behavior, however then I get:

      org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new groovy.json.JsonSlurperClassic
      

      None of these errors show up in the script approval queue, so I can't whitelist them myself. Please add new JsonSlurperClassic and/or new HashMap to the default whitelist. This will block my upgrade to 2.x otherwise.

          [JENKINS-35140] JsonSlurper does not work after updating to Jenkins 2.x

          Andrew Bayer added a comment -

          Andrew Bayer added a comment - PR up at https://github.com/jenkinsci/script-security-plugin/pull/77

          Jesse Glick added a comment -

          None of these errors show up in the script approval queue

          Are you sure? If that is reproducible, it is certainly a bug I would want to diagnose and fix ASAP. I would need complete steps to reproduce from scratch.

          The NotSerializableException is best worked around by encapsulating the logic which deals with JsonSlurper in a method marked @NonCPS and taking/returning serializable data types.

          Jesse Glick added a comment - None of these errors show up in the script approval queue Are you sure ? If that is reproducible, it is certainly a bug I would want to diagnose and fix ASAP. I would need complete steps to reproduce from scratch. The NotSerializableException is best worked around by encapsulating the logic which deals with JsonSlurper in a method marked @NonCPS and taking/returning serializable data types.

          Jacob Fike added a comment -

          After adding a lot more try/catch blocks to my files, I discovered the issue was not when attempting to load the library with the JsonSlurper code:

          @NonCPS
          def parseJson(text) {
            return new JsonSlurper().parseText(text)
          }
          

          The error actually happens when trying to run a different method in the library that itself calls parseJson() but is not marked @NonCPS . Even though this second method did not return anything, it complained about the LazyMap not being serializable. Adding @NonCPS to every method in the library seems to fix the issue.

          Jacob Fike added a comment - After adding a lot more try/catch blocks to my files, I discovered the issue was not when attempting to load the library with the JsonSlurper code: @NonCPS def parseJson(text) { return new JsonSlurper().parseText(text) } The error actually happens when trying to run a different method in the library that itself calls parseJson() but is not marked @NonCPS . Even though this second method did not return anything, it complained about the LazyMap not being serializable. Adding @NonCPS to every method in the library seems to fix the issue.

          I cannot get it to work:

          node{
             echo parseText(' { "foo": "bar" } ') // prints null
          }
          
          @NonCPS
          def parseText(txt){
              return new groovy.json.JsonSlurper().parseText(txt)
          }
          

          Jenkins 2.6 / 2.7
          Pipeline 2.1

          No exceptions, pipeline finishes successfully

          Zhelyan Panchev added a comment - I cannot get it to work: node{ echo parseText( ' { "foo" : "bar" } ' ) // prints null } @NonCPS def parseText(txt){ return new groovy.json.JsonSlurper().parseText(txt) } Jenkins 2.6 / 2.7 Pipeline 2.1 No exceptions, pipeline finishes successfully

          Jesse Glick added a comment -

          A @NonCPS method must return a Serializable result, so you need to do more extensive processing inside these methods before passing results to the main script.

          Jesse Glick added a comment - A @NonCPS method must return a Serializable result, so you need to do more extensive processing inside these methods before passing results to the main script.

          weird but now it works in Jenkins 2.7 with or without @NonCPS.. I don't think anything changed apart from restarting Jenkins couple of times and upgrading https://github.com/jenkinsci/pipeline-build-step-plugin to 2.1

          Zhelyan Panchev added a comment - weird but now it works in Jenkins 2.7 with or without @NonCPS .. I don't think anything changed apart from restarting Jenkins couple of times and upgrading https://github.com/jenkinsci/pipeline-build-step-plugin to 2.1

          Anudeep Lalam added a comment - - edited

          Hi,

          I am also facing this issue. Can someone please share the workaround for this.

          When I use below method after parsing the JSON, I am getting java.io.NotSerializableException: groovy.json.internal.LazyMap error.
          If I just try to print the values of the JSON, I am not getting any error

          variables = parseText(new File('/Build/variables.json').text)
          platforms = parseText(new File('Build/platforms.json').text)
          	
          def parseText(txt){
              return new groovy.json.JsonSlurper().parseText(txt)
          }
          
          gitUrl = variables.git.url
          gitCred = variables.git.credential
          gitBranch = variables.git.branch
          unixws = variables.ws.unix
          
          def gitCheckOut(String wsPath, String url, String cred, String branch) {
          	try {
          		ws("$wsPath") {
          			git ([url: "$url", credentialsId: "$cred", branch: "$branch"])
          		}
          	} catch (Exception ex) {
          		echo ex.getMessage()
          		gitCoErrors = gitCoErrors + "$wsPath\n"
          	}
          }
          
          
          node("HOST1") {
          	gitCheckOut("$unixws","$gitUrl","gitCred","$gitBranch")
          }
          

          Anudeep Lalam added a comment - - edited Hi, I am also facing this issue. Can someone please share the workaround for this. When I use below method after parsing the JSON, I am getting java.io.NotSerializableException: groovy.json.internal.LazyMap error. If I just try to print the values of the JSON, I am not getting any error variables = parseText( new File( '/Build/variables.json' ).text) platforms = parseText( new File( 'Build/platforms.json' ).text) def parseText(txt){ return new groovy.json.JsonSlurper().parseText(txt) } gitUrl = variables.git.url gitCred = variables.git.credential gitBranch = variables.git.branch unixws = variables.ws.unix def gitCheckOut( String wsPath, String url, String cred, String branch) { try { ws( "$wsPath" ) { git ([url: "$url" , credentialsId: "$cred" , branch: "$branch" ]) } } catch (Exception ex) { echo ex.getMessage() gitCoErrors = gitCoErrors + "$wsPath\n" } } node( "HOST1" ) { gitCheckOut( "$unixws" , "$gitUrl" , "gitCred" , "$gitBranch" ) }

          Jesse Glick added a comment -

          Better to use, say, jq from a sh step to extract desired fields.

          Jesse Glick added a comment - Better to use, say, jq from a sh step to extract desired fields.

          Steve Prentice added a comment - - edited

          Posting this here as I recently had to work around this issue:

          @NonCPS
          def parseJson(jsonString) {
              // Would like to use readJSON step, but it requires a context, even for parsing just text.
              def lazyMap = new JsonSlurper().parseText(jsonString)
              
              // JsonSlurper returns a non-serializable LazyMap, so copy it into a regular map before returning
              def m = [:]
              m.putAll(lazyMap)
              return m
          }
          

          Steve Prentice added a comment - - edited Posting this here as I recently had to work around this issue: @NonCPS def parseJson(jsonString) { // Would like to use readJSON step, but it requires a context, even for parsing just text. def lazyMap = new JsonSlurper().parseText(jsonString) // JsonSlurper returns a non-serializable LazyMap, so copy it into a regular map before returning def m = [:] m.putAll(lazyMap) return m }

          one can now use readJSON for this:

          import groovy.json.*
          node('master') {
          stage("test")

          { def rc = ['mac':['CO_SS': false, 'CO_SSxx': true]] jstr = new JsonBuilder(rc).toPrettyString() writeFile file:'test.json', text: jstr stash "test.json" unstash "test.json" def jsonText = readJSON file:"test.json" print(jsonText) print(jsonText['mac']) }

          }

          Wilfried Goesgens added a comment - one can now use readJSON for this: import groovy.json.* node('master') { stage("test") { def rc = ['mac':['CO_SS': false, 'CO_SSxx': true]] jstr = new JsonBuilder(rc).toPrettyString() writeFile file:'test.json', text: jstr stash "test.json" unstash "test.json" def jsonText = readJSON file:"test.json" print(jsonText) print(jsonText['mac']) } }

            abayer Andrew Bayer
            jacobfike Jacob Fike
            Votes:
            1 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: