Issue Update Error after copying value from one insight custom field to another in scriptrunner post

Marco Hasenfratz
Contributor
July 21, 2022

Hi all, 

 

i have to copy a value from one Insight Custom Filed to another in the same issue

Tried the corresponding build in Scriptrunner script, with this, something is happening, but it only sets the Attributes from the source customfield in to the target custom field. 

But as this two custom fields have not all attributes the same i need not just a copy of the existing values, i wanna force Jira to choose the right insight entry and display then the attributes in the target Custom field (same if the user would choose the entry manually) 

I tried this way:

import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade

import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade

import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade

import com.atlassian.jira.event.type.EventDispatchOption                    // Update Issue (customField)

import com.atlassian.jira.issue.CustomFieldManager

import com.atlassian.jira.issue.fields.ImmutableCustomField

import com.atlassian.jira.issue.fields.CustomField

import com.atlassian.jira.bc.issue.search.SearchService                     // run JQL

import com.atlassian.jira.jql.parser.JqlQueryParser                         // run JQL

import com.atlassian.jira.web.bean.PagerFilter                              // run JQL

def issueManager = ComponentAccessor.issueManager

def CustomFieldManager = ComponentAccessor.getCustomFieldManager();

def userUtil = ComponentAccessor.getUserUtil();

@WithPlugin("com.riadalabs.jira.plugins.insight")

@PluginModule IQLFacade iqlFacade

@PluginModule ObjectFacade objectFacade

@PluginModule ObjectTypeAttributeFacade objectTypeAttributeFacade

def issue = issueManager.getIssueObject("ISSP-4904") // your issue key here

//CustomField Manager

def customFieldManager = ComponentAccessor.getCustomFieldManager()

// This gets data from the corresponding Customer Field

def customerCF = (CustomFieldManager.getCustomFieldObjectsByName("Customer"))[0];

def String customerStr = issue.getCustomFieldValue(customerCF);

def String customerID = customerStr.substring(customerStr.indexOf("-") + 1, customerStr.indexOf(")")); //gets only value in (..)

def int customerNR = customerID.toInteger()

log.warn(customerStr)

log.warn(customerID)

log.warn(customerNR)

def objectAttributeUserID = objectFacade.loadObjectAttributeBean(customerNR, 860)

def String objectAttributeUserIDValue = objectAttributeUserID.getObjectAttributeValueBeans()[0].getValue()

log.warn(objectAttributeUserID)

log.warn(objectAttributeUserIDValue)

def iamuserCF = ComponentAccessor.customFieldManager.getCustomFieldObject(11601)

log.warn(objectAttributeUserIDValue)

issue.setCustomFieldValue(iamuserCF,objectAttributeUserID)

//This method will store the provided issue to the JIRA datastore.

issueManager.updateIssue(userUtil.getUserByName("Jira Automation"), issue, EventDispatchOption.DO_NOT_DISPATCH, false)

 

... but I'm always struggling with the last line, the update code:

issueManager.updateIssue(userUtil.getUserByName("Jira Automation"), issue, EventDispatchOption.DO_NOT_DISPATCH, false)

 

it gets me this error:

2022-07-22 07:56:26,810 ERROR [common.UserScriptEndpoint]: Script console script failed: java.lang.ClassCastException: class com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean cannot be cast to class java.util.Collection (com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean is in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @3e20abcb; java.util.Collection is in module java.base of loader 'bootstrap') at com.riadalabs.jira.plugins.insight.services.jira.customfield.DefaultObjectCustomField.updateValue(DefaultObjectCustomField.java:87) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:430) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:400) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateFieldValues(DefaultIssueManager.java:716) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:667) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:653) at com.atlassian.jira.issue.managers.RequestCachingIssueManager.updateIssue(RequestCachingIssueManager.java:217) at com.atlassian.jira.issue.IssueManager$updateIssue$30.call(Unknown Source) at Script1204.run(Script1204.groovy:56)

 

I also tried to use other attribute values which are available on both fields - even the copy "Label" to "Label" Attribute is not working... 

 

Is there a way to do this? 
Thank you in advance
Regards Marco

1 answer

1 accepted

0 votes
Answer accepted
Peter-Dave Sheehan
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
July 22, 2022

Hi Marco

The clue in your error is

ObjectAttributeBean cannot be cast to class java.util.Collection 

This is saying that you are trying to store an ObjectAttributeBean but Jira expects some kind of "Collection".

Specifically, Insight Customer fields can only accept collections of ObjectBean (even if multiple is not enabled, then you need a collection of size 1).

So we need to find the part of your script that generates the ObjectAttributeBean and make sure you retrieve the value from it (I assume that's a reference attribute and therefore the value will be an object reference)

Here is a fixed (and a bit cleaned up) version of your script

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.riadalabs.jira.plugins.insight.services.model.ObjectBean

def issueManager = ComponentAccessor.issueManager
def customFieldManager = ComponentAccessor.customFieldManager
def automationUser = ComponentAccessor.userManager.getUserByName('Jira Automation')

@WithPlugin("com.riadalabs.jira.plugins.insight")
@PluginModule ObjectFacade objectFacade

def issue = issueManager.getIssueObject("ISSP-4904") // your issue key here

// This gets data from the corresponding Customer Field
def customerCF = customFieldManager.getCustomFieldObjectsByName("Customer")[0]
//insight fields store array of ObjectBeanss
def
customerObjects = issue.getCustomFieldValue(customerCF) as List<ObjectBean>
def customerObject = customerObjects[0] //assume single customer

log.warn("customerObject has key=$customerObject.objectKey, id=$customerObject.id, and label=$customerObject.label")

def objectAttributeUserID = objectFacade.loadObjectAttributeBean(customerObject.id, 860)
def referencedUserObjectId = objectAttributeUserID.objectAttributeValueBeans[0].referencedObjectBeanId
def referenceUserObject = objectFacade.loadObjectBean(referencedUserObjectId)
log.warn("referenceUserObject has key=$referenceUserObject.objectKey, id=$referenceUserObject.id, and label=$referenceUserObject.label")

def iamuserCF = ComponentAccessor.customFieldManager.getCustomFieldObject(11601)

issue.setCustomFieldValue(iamuserCF, [referenceUserObject])
//This method will store the provided issue to the JIRA datastore.
issueManager.updateIssue(automationUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false)

A few pointers

def String ... is like saying def def or String String. If you want to set the type of a variable, just declare it with that type, don't include def. def is used to declare an untyped object variable that can change the underlying type at will during runtime.

Don't type cast the getCustomFieldValue to String, especially if it's not a simple text field.
By keeping it as "def" and adding the type we expect with the "as List<ObjectBean>" at the end, we can tell the compiler what to expect.
But bonus, you now have access to methods like getId() or getObjectKey() or getLabel() of objectBean as you'll see in the log.warn statement.
And there is no longer any need for fancy string manipulation to get the id.

We can replace getValue with getReferenceObjectBeanId so that we can get a property typed integer value for the reference.
Which allows us to load a new objectbean.

Then we can apply objectbean as a list (surrounded by []) to the custom field.

Final pointer, after doing all that above, you index will not be updated. So searches will not work until the issue is re-indexed for another reason.
I've taken to using issueService instead of issueManager wherever I can.
To do that, use the following line instead of your last 2:

def issueService = ComponentAccessor.issueService
def iip = issueService.newIssueInputParameters()
iip.setSkipScreenCheck(true) //optional
iip.addCustomFieldValue(iamuserCF.id, referenceUserObject.objectKey)
def validationResult = issueService.validateUpdate(automationUser, issue.id, iip)
assert validationResult.valid : validationResult.errorCollection.errors
issueService.update(automationUser, validationResult, EventDispatchOption.DO_NOT_DISPATCH,false)

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events