How can I define a class in a Jenkins shared library that contains an empty JSON object?
// src/org/build/Report.groovy
package org.build
public class Report implements Serializable {
def steps
def json
Report(steps) {
this.steps = steps
this.json = emptyJson()
}
@NonCPS
def emptyJson() {
return this.steps.readJSON( text: '{}' )
}
}
...is instantiated from this pipeline:
@Library('my-library')
import org.build.Report
pipeline {
agent any
stages {
stage("foo") {
steps {
script {
rep = new org.build.Report(this)
}
}
}
}
}
...and fails with the error: expected to call org.build.Report.<init> but wound up catching readJSON; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/
I had only earlier today thought I'd figured out how to solve this "class" of problem.
Earlier, I encountered the same error when invoking a shared-library function from a shared-library class. I fixed that problem per the guidance at the link that the error message noted, i.e. annotating the shared-library function with @NonCPS
.
I.e. in the code below, class FirstClass
is able to invoke function firstNonNull()
because the function is annotated with @NonCPS
; without the annotation, this code generated the same error as in the question above:
// src/org/example/FirstClass.groovy
package org.example
public class FirstClass implements Serializable {
def steps
def var
FirstClass(steps) {
this.steps = steps
this.var = steps.utils.firstNonNull( [null, null, "assigned_from_ctor"] )
}
}
// vars/utils.groovy
@NonCPS
def firstNonNull( arr ) {
for ( def i in arr ) { if ( i ) { return i } }
return null
}
@Library('my-library')
import org.example.FirstClass
pipeline {
agent any
stages {
stage("foo") {
steps {
script {
first_class = new org.example.FirstClass(this)
}
}
}
}
}
Why does this approach not work with the Report
class invoking readJSON
?