3

There are plenty of discussion about what it means and what to do about it, however the main solution of using @NonCPS doesn't seem to work. Here's the relevant piece of the code:

@NonCPS def restCall(String method, String resource, String data = '') { def URL url = new URL("${Params.REST_BASE_URI}/${resource}") def HttpURLConnection connection = url.openConnection() withCredentials([usernamePassword(credentialsId: 'restful-api', passwordVariable: 'RA_PASS', usernameVariable: 'RA_USER')]) { String encoded = Base64.getEncoder().encodeToString(("${env.RA_USER}:${env.RA_PASS}").getBytes(StandardCharsets.UTF_8)) connection.setRequestProperty("Authorization", "Basic ${encoded}"); } connection.setRequestProperty("content-type", "application/json"); connection.setRequestMethod(method) connection.doOutput = true if (data != '') { def writer = new OutputStreamWriter(connection.outputStream) writer.write(data) writer.flush() writer.close() } connection.connect(); def statusCode = connection.responseCode if (statusCode != 200 && statusCode != 201) { throw new Exception(connection.getErrorSteam().text) } return connection.content.text } 

Note that it does have @NonCPS on the function. However executing this still produces the same error:

an exception which occurred: in field groovy.lang.Reference.value in object groovy.lang.Reference@1375b00 in field WorkflowScript$_bitbucketCall_closure1.connection in object WorkflowScript$_bitbucketCall_closure1@b3001c in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@144b2a6 in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@144b2a6 Caused: java.io.NotSerializableException: sun.net.www.protocol.https.HttpsURLConnectionImpl at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860) at ... 

How can I solve it?

3
  • Marking the method as @NonCPS would only apply to the method itself I would think. That would then not apply to the scope of URL.openConnection(), which does not seem to be serializable. That being said, I hope someone knows how to solve this because global vars to create REST API calls are going to be rather helpful in jenkins-pipeline. Commented Nov 8, 2018 at 13:37
  • What I can see is that you’re calling some pipeline methods from within the NonCPS method. That’s neither supported or will work. However I think that the reason for the exception is not to search here but in the remaining code which is not marked as NonCPS. To support you there please submit the calling code as well. Commented Nov 10, 2018 at 10:31
  • @I don't think calling code has anything to do with it, as the stacktrace points to HTTPUrlConnection class. In any event, an example calling code would be def result = restCall('GET', 'info') Commented Nov 12, 2018 at 11:28

1 Answer 1

13

Turns out, the @NonCPS annotation isn't needed to achieve what I'm after. Instead, all I need to do is to ensure that the there are no non-serializable variables still initialised at the end of the method call. Therefore the following method works fine:

def restCall(String method, String resource, String data = '') { def URL url = new URL("${Params.REST_BASE_URI}/${resource}") def HttpURLConnection connection = url.openConnection() withCredentials([usernamePassword(credentialsId: 'restful-api', passwordVariable: 'RA_PASS', usernameVariable: 'RA_USER')]) { String encoded = Base64.getEncoder().encodeToString(("${env.RA_USER}:${env.RA_PASS}").getBytes(StandardCharsets.UTF_8)) connection.setRequestProperty("Authorization", "Basic ${encoded}"); } connection.setRequestProperty("content-type", "application/json"); connection.setRequestMethod(method) connection.doOutput = true if (data != '') { def writer = new OutputStreamWriter(connection.outputStream) writer.write(data) writer.flush() writer.close() } connection.connect(); def statusCode = connection.responseCode if (statusCode != 200 && statusCode != 201) { String text = connection.getErrorStream().text connection = null throw new Exception(text) } String text = connection.content.text connection = null } 

The trick is to explicitly set connection = null before the end of the execution of the method.

Sign up to request clarification or add additional context in comments.

3 Comments

This Q&A is from several years ago, but by any chance, do you know/do you have access to the version of Jenkins you used? I am facing the exact same issue, and eagerly tried your solution, but I still get the NotSerializableException. I've literally copy/pasted the restCall() function from your answer verbatim into my Jenkins shared lib, and called my_shared_lib.restCall(...), but the exception still occurs. I'm using Jenkins server version 2.222.3, which has Groovy version 2.4.12. Do you think the Jenkins/Groovy versions are relevant?
@StoneThrow Same for me on Jenkins 2.289.1: ...Caused: java.io.NotSerializableException: sun.net.www.protocol.https.HttpsURLConnectionImpl Any luck finding a solution for this problem?
After some testing I found out that if you remove the Jenkins step withCredentials from above code it will work again. Putting that step into the caller function worked fine for me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.