ClassCastException When Instantiating Script Include in Transform Map Script

nodisplay
Giga Contributor

Hello! I am trying to use a script include I've written to make an API call to populate a field during an import and I keep getting "Import set: ISETXXXXX transform stopped due to error: com.glide.rest.outbound.scriptable.ScriptableRESTResponse cannot be cast to com.glide.script.adaptors.WSResult" (see below for full error). The script include works elsewhere in ServiceNOW, including background scripts, workflows, and UI actions, so I don't think it's an error in there. I'm using an onBefore transform script that is very simple (see below, with sensitive data changed of course). I've included all of my various attempts at getting this to work and none of them do. The error I get is below the code example.

(function runTransformScript(source, map, log, target /*undefined onStart*/ ) {
    target.u_imported = true;

    var grCI = new GlideRecord('cmdb_ci_server');
    grCI.addQuery('name', source.u_configuration_item);
    grCI.query();
    if (grCI.next()) {
        // These work fine
        target.u_operating_system = grCI.os;
        target.u_server_assignment_group = grCI.assignment_group;
        target.u_server_support_group = grCI.support_group;

//      tried both of the below in combo with the various code attempts below these, no luck
//      gs.include('global.MyScriptInclude');
//      gs.include('MyScriptInclude');

//      var si = new MyScriptInclude();
//      gs.info('SI type: ' + typeof si);  // gives "object" but still fails

//      var si = new global.MyScriptInclude();  // Doesn't work
//      var si = new MyScriptInclude();  // Doesn't work
//      target.my_field = new MyScriptInclude().doApiCall(grCI.name); // Doesn't work
//      var my_var = new MyScriptInclude().doApiCall(grCI.name);  // Doesn't work
//      target.my_field = my_var;  // Record never gets updated/inserted
//      gs.info('my_var: ' + my_var);  // Logs the correct value returned from doApiCall() - boolean true, but still fails
//      new MyScriptInclude();  // Doesn't work

        // A test script include that just returns a string, this works
        var testSI = new test_si();
        gs.info('testSI: ' + testSI.getTestString());

        // I also tried using the sn_ws.RESTMessageV2() object to do a call manually and that works, and it's just copy/pasted from my script include.
    }

})(source, map, log, target);

My error, which gives me no clue about where in my script it's failing (though from my experimentation it seems to be when I instantiate the script include object, even though the subsequent call seems to work (see above code for example)) (Source == ImportSetTransformer, Level == Error):

Import set: ISET0044717 transform stopped due to error: com.glide.rest.outbound.scriptable.ScriptableRESTResponse cannot be cast to com.glide.script.adaptors.WSResult

java.lang.ClassCastException: com.glide.rest.outbound.scriptable.ScriptableRESTResponse cannot be cast to com.glide.script.adaptors.WSResult
at com.glide.db.impex.transformer.TransformerScript.setResponseElements(TransformerScript.java:111)
at com.glide.db.impex.transformer.TransformerScript.setStatusMessage(TransformerScript.java:95)
at com.glide.db.impex.transformer.TransformerScript.runScript(TransformerScript.java:73)
at com.glide.db.impex.transformer.TransformerScript.runWhenScript(TransformerScript.java:133)
at com.glide.db.impex.transformer.Transformer.runOnBeforeScript(Transformer.java:310)
at com.glide.db.impex.transformer.Transformer.transformBatch(Transformer.java:162)
at com.glide.db.impex.transformer.Transformer.transform(Transformer.java:88)
at com.glide.system_import_set.ImportSetTransformerImpl.transformEach(ImportSetTransformerImpl.java:304)
at com.glide.system_import_set.ImportSetTransformerImpl.transformAllMaps(ImportSetTransformerImpl.java:117)
at com.glide.system_import_set.ImportSetTransformerWorker.startWork(ImportSetTransformerWorker.java:40)
at com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:126)
at com.glide.worker.ProgressWorker.startAndWait(ProgressWorker.java:52)
at com.glide.worker.BackgroundProgressJob.execute(BackgroundProgressJob.java:59)
at com.glide.schedule.JobExecutor.lambda$executeJob$0(JobExecutor.java:113)
at com.glide.schedule.JobExecutor.executeJob(JobExecutor.java:116)
at com.glide.schedule.JobExecutor.execute(JobExecutor.java:100)
at com.glide.schedule_v2.SchedulerWorkerThread.executeJob(SchedulerWorkerThread.java:300)
at com.glide.schedule_v2.SchedulerWorkerThread.lambda$process$0(SchedulerWorkerThread.java:188)
at com.glide.worker.TransactionalWorkerThread.executeInTransaction(TransactionalWorkerThread.java:35)
at com.glide.schedule_v2.SchedulerWorkerThread.process(SchedulerWorkerThread.java:188)
at com.glide.schedule_v2.SchedulerWorkerThread.run(SchedulerWorkerThread.java:102)

I've done extensive googling and cannot find anything related to this issue. Can anyone help explain this and offer a potential solution? Thank you very much!

1 ACCEPTED SOLUTION

Welp, after a bunch more testing with a lot of log statements and removing lines until I found the culprit, I humbly acknowledge that you were right. The line in my SI:

response = sm.execute();

needed to be

var response = sm.execute();

What boggles my mind is why that's not caught in the background scripts, workflows, or business rules I've used it in, but the import transform map fails because of it.

 

Anyway, thank you for your help and for pushing me to reevaluate my script include.

View solution in original post

6 REPLIES 6

Chris Sanford
Giga Guru

Ok well probably, it's the script include

Like I said in my original post, the script include works everywhere else as-is, and copy/pasting the code into the transform map works too. The issue seems to be how it's being instantiated or something, and the error implies that the SI object is getting cast to something I don't recognize. Also, nowhere in the error does it give mention of the script include, so I'm really not sold on it being an error in that SI code.

Ok but my doubt is because I have used other script includes in before transform script fine but it's possible it's something else. Could you share the script include and maybe an example of background script where it works

Sure, below is the constructor for the SI and the functions it calls (names changed, of course, and sorry if the formatting is off, I'm new to this interface):

var MySI = Class.create();
MySI.prototype = {
    initialize: function() {
		this.un = gs.getProperty('sa_un');
		this.pw = gs.getProperty('sa_pw');
		this.server = gs.getProperty('server');
		this.midserver = gs.getProperty('midserver');
		this.session = '';
		this.log_id = 'MySI';
		this.getSession();
	},


// Gets a new session token, returns true on success
	getSession : function() {
		try {
			var headers = [[]];
			var endpoint = 'api/v2/session/login';
			var body = JSON.stringify({"username" : this.un, "password" : this.pw});
			var responseBody = this.doRequest('post', endpoint, headers, body);
			var jsonResponse = JSON.parse(responseBody);
			if (jsonResponse.data && jsonResponse.data.session) {
				this.session = jsonResponse.data.session;
				return true;
			}
			gs.log('(getSession) ERROR: Could not start session.', this.log_id);
			return false;
		} catch (ex) {
			this.session = '';
			gs.log('(getSession) EXCEPTION: ' + ex, this.log_id);
			gs.log('(getSession) EXCEPTION (2) responseBody: ' + responseBody, this.log_id);
			return false;
		}
	},


	doRequest : function(method, endpoint, headers, body) {		
		var responseBody;
		var status;
		var sm;
		try {
			sm = new sn_ws.RESTMessageV2();
			sm.setHttpMethod(method);
			sm.setEndpoint(this.server + endpoint);
			
			// set the body if there is one
			if (body != '') sm.setRequestBody(body);
			
			// Set the headers
			for (var i = 0; i < headers.length; i++) {
				// Should always be an array of key-pair string values
				sm.setRequestHeader(headers[i][0], headers[i][1]);
			}
			sm.setMIDServer(this.midserver);
			sm.setEccParameter('skip_sensor', 'true');
			// Might throw exception if http connection timed out or some issue with sending request 
			// itself because of encryption/decryption of password.
			response = sm.execute();

			// In seconds. Wait at most 60 seconds to get response from ECC Queue/Mid Server 
			// Might throw exception timing out waiting for response in ECC queue.
			response.waitForResponse(60);
//			gs.log('(doRequest) Request result: ' + response.getBody(), this.log_id);
			responseBody = response.haveError() ? response.getErrorMessage() : response.getBody();
			status = response.getStatusCode();
		} catch(ex) {
			responseBody = ex.message;
			gs.log('(doRequest) EXCEPTION: ' + ex + ' - Response body: ' + responseBody, this.log_id);
			//return 'ERROR ' + status + ': "' + responseBody + '"';
			return false;
		} finally {
			requestBody = sm ? sm.getRequestBody() : null;
		}
		return responseBody;
	},


	getSessionId : function() {
		return this.session;
	},
    type: 'MySI'
};

 

Background script where it works:

var mySI = new MySI();
gs.print(mySI.getSessionId());  // Returns the correct session ID

 

I hope this helps. Thanks for your attention, I do appreciate the assistance.