Hobin C.
Hobin C.

Reputation: 761

java.io.NotSerializableException: java.time.format.DateTimeFormatter

I am new in Jenkins. The codes below is to construct a simple command and pass this command , which is java.lang.String type, to the next job. My question is that the data exchange between this Jenkins-pipeline and the Jenkins-job 'email_job' only contains string (java.lang.String) which should be serializable. However, this script throw the exception java.io.NotSerializableException: java.time.format.DateTimeFormatter.

If removing the build-step in the below script, this Jenkins-pipeline works fine. My Jenkins version is 2.138.4. Any clues?

import java.net.URLEncoder
// Jenkins pipeline
pipeline {
    agent any
    stages {
        stage('main') {
            steps {
                println '------------------ main-stage ------------------'
                script {
                    def r_ptr = java.time.LocalDateTime.now()
                    def l_ptr = r_ptr.minusDays(14) as java.time.LocalDateTime
                    def fmt4time = 'yyyy-MM-dd HH:mm:ss'
                    def fmt2cnv = java.time.format.DateTimeFormatter.ofPattern(fmt4time)  // formatter for conversion
                    def l_str4tz = l_ptr.format(fmt2cnv)
                    def r_str4tz = r_ptr.format(fmt2cnv)
                    l_str4tz = '2020-02-18 00:00:00'
                    r_str4tz = '2020-03-18 00:00:00'
                    //
                    def ip4server = '127.0.0.1'
                    def qry_info = []
                    def __qry = ''
                    __qry = URLEncoder.encode(l_str4tz, 'UTF-8').replace('+', '%20')
                    __qry = "start_time=${__qry}"
                    qry_info.push(__qry)
                    __qry = URLEncoder.encode(r_str4tz, 'UTF-8').replace('+', '%20')
                    __qry = "end_time=${__qry}"
                    qry_info.push(__qry)
                    def qry_opts = qry_info.join('&')
                    def __cmd = ''
                    __cmd = "curl --get http://${ip4server}/dsb4bbu?" + qry_opts
                    build (
                        job: 'email_job',
                        parameters: [
                            string(name: 'param01', value: "11112222"),
                            string(name: 'cmd', value: "${__cmd}"),
                        ]
                    )
                }
            }
        }
    }
}

Upvotes: 0

Views: 1665

Answers (1)

zett42
zett42

Reputation: 27766

Pipeline restricts all variables to Serializable types (see Best Practices for Scalable Pipeline Code).

I suggest to extract the code that prepares the build parameters into a function annotated with @NonCPS (prevent CPS transformation). Within this function you are not restricted to serializable variables, but there is a different limitation, you cannot call pipeline steps and other functions that don't have @NonCPS annotation, except for some simple ones like echo (see Pipeline CPS method mismatches).

I think it's also a better code style to only have high-level code within the pipeline{} block (single level of abstraction principle).

import java.net.URLEncoder
// Jenkins pipeline
pipeline {
    agent any
    stages {
        stage('main') {
            steps {
                println '------------------ main-stage ------------------'
                script {
                    build (
                        job: 'email_job',
                        parameters: [
                            string(name: 'param01', value: "11112222"),
                            string(name: 'cmd', value: prepareCmd()),
                        ]
                    )
                }
            }
        }
    }
}

@NonCPS
String prepareCmd() {
    def r_ptr = java.time.LocalDateTime.now()
    def l_ptr = r_ptr.minusDays(14) as java.time.LocalDateTime
    def fmt4time = 'yyyy-MM-dd HH:mm:ss'
    def fmt2cnv = java.time.format.DateTimeFormatter.ofPattern(fmt4time)  // formatter for conversion
    def l_str4tz = l_ptr.format(fmt2cnv)
    def r_str4tz = r_ptr.format(fmt2cnv)
    l_str4tz = '2020-02-18 00:00:00'
    r_str4tz = '2020-03-18 00:00:00'
    //
    def ip4django = '127.0.0.1'
    def qry_info = []
    def __qry = ''
    __qry = URLEncoder.encode(l_str4tz, 'UTF-8').replace('+', '%20')
    __qry = "start_time=${__qry}"
    qry_info.push(__qry)
    __qry = URLEncoder.encode(r_str4tz, 'UTF-8').replace('+', '%20')
    __qry = "end_time=${__qry}"
    qry_info.push(__qry)
    def qry_opts = qry_info.join('&')
    return "curl --get http://${ip4server}/dsb4bbu?" + qry_opts
}

Upvotes: 2

Related Questions