Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How to keep existing Asset attribute values while adding another value using Groovy script

Marlee Pitts December 19, 2022

I'm trying to add additional attribute values to an existing attribute using a groovy script post function. The following script adds the value we want but overwrites the existing values that we want to keep. How do I stop it from removing the existing values? Is there a way I can add anything to my script?

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.fields.CustomField;

/* Get Insight Object Facade from plugin accessor */
Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade");
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass);

/* Get Insight Object Attribute Facade from plugin accessor */
Class objectTypeAttributeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade");
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeAttributeFacadeClass);

/* Get the factory that creates Insight Attributes */
Class objectAttributeBeanFactoryClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory");
def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(objectAttributeBeanFactoryClass);

/* This is the custom field with the value you want to add to an object attribute */
CustomField jiraCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14932); // Change 12345 to the correct value

/* This is the custom field where the object/s you want to set the value */
CustomField insightCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14930); // Change 23456 to the correct value
def insightObjects = issue.getCustomFieldValue(insightCustomField); // "issue" variable is always accessible in post function scripts.

/* This is the priority object type attribute and the one we want to modify */
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(379);


if (insightObjects != null) {
insightObjects.each{insightObject ->
/* Create the new attribute bean based on the value */
def newValue = issue.getCustomFieldValue(jiraCustomField);
def newObjectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, newValue[0].getName());
/* Load the attribute bean */
def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.getId(), objectTypeAttributeBean.getId());
if (objectAttributeBean != null) {
/* If attribute exist reuse the old id for the new attribute */
newObjectAttributeBean.setId(objectAttributeBean.getId());
}
/* Store the object attribute into Insight. */
try {
objectAttributeBean = objectFacade.storeObjectAttributeBean(newObjectAttributeBean);
} catch (Exception vie) {
log.warn("Could not update object attribute due to validation exception:" + vie.getMessage());
}
}
}



/* Done! :) */
return true;

3 answers

0 votes
PD 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.
December 20, 2022

Here is another version that should work better:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
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
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory

/* Get Insight Facades and Factories from plugin accessor */
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade)
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectTypeAttributeFacade)
def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectAttributeBeanFactory)

/* This is the custom field with the value you want to add to an object attribute */
CustomField jiraCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14932) // Change 12345 to the correct value

/* This is the custom field where the object/s you want to set the value */
CustomField insightCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14930) // Change 23456 to the correct value
def insightObjects = issue.getCustomFieldValue(insightCustomField) // "issue" variable is always accessible in post function scripts.

/* This is the priority object type attribute and the one we want to modify */
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(379)

if (insightObjects != null) {
insightObjects.each { ObjectBean insightObject ->
def newValue = issue.getCustomFieldValue(jiraCustomField)
/* Load the attribute bean */
def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.id, objectTypeAttributeBean.id)
if (!objectAttributeBean) {
/* If attribute doesn't exist create one */
objectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, newValue[0].name)
} else {
/* If attribute exists, check if the value is not already present and add it if needed */
if(objectAttributeBean.objectAttributeValueBeans.any{it.value == newValue[0].name }) {
/* Value already present, return null to end this each iteration */
return null
}
//created a version of the objectAttributeBean that can be modified
objectAttributeBean = objectAttributeBean.createMutable()
//extract the current list of values
def values = objectAttributeBean.objectAttributeValueBeans

//create a valueBean for the new entry
def objectAttributeValueBean = objectAttributeBean.createObjectAttributeValueBean()
objectAttributeValueBean.setValue(objectTypeAttributeBean,newValue[0].name)

//add the new entry to the list of values
values.add(objectAttributeValueBean)
//update the objectAttribute with the new list of values.
objectAttributeBean.setObjectAttributeValueBeans(values)
}

/* Store the object attribute into Insight. */
try {
objectAttributeBean = objectFacade.storeObjectAttributeBean(objectAttributeBean)
} catch (Exception vie) {
log.warn("Could not update object attribute due to validation exception:$vie.message")
}
}
}
0 votes
Marlee Pitts December 20, 2022

@PD Sheehan 

Thank you! I tried your modifications and I get an error on line 39 objectAttributeBean.objectAttributeValueBeans.add(objectAttributeValueBean)

Message:
java.lang.UnsupportedOperationException
Stack:
java.base/java.util.AbstractList.add(Unknown Source)
java.base/java.util.AbstractList.add(Unknown Source)
java_util_List$add.call(Unknown Source)
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
script_5cb834065217c5f3fa91b1c89d2c3889$_run_closure1.doCall(script_5cb834065217c5f3fa91b1c89d2c3889.groovy:39)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.base/java.lang.reflect.Method.invoke(Unknown Source)
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
groovy.lang.Closure.call(Closure.java:405)
groovy.lang.Closure.call(Closure.java:421)
org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2331)
org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2316)
org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2357)
org.codehaus.groovy.runtime.dgm$186.invoke(Unknown Source)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:244)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
script_5cb834065217c5f3fa91b1c89d2c3889.run(script_5cb834065217c5f3fa91b1c89d2c3889.groovy:24)
0 votes
PD 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.
December 19, 2022

Hello Marlee

Welcome to the community.

First off, I don't know why the documentation recommends using the classLoader to get riadalabs classes.

In my experience, the following works just as well:

import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade)

Anyway, re-ordering and modifying your code, I came up with this (untested):

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
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
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory

/* Get Insight Facades and Factories from plugin accessor */
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade)
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectTypeAttributeFacade)
def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectAttributeBeanFactory)

/* This is the custom field with the value you want to add to an object attribute */
CustomField jiraCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14932) // Change 12345 to the correct value

/* This is the custom field where the object/s you want to set the value */
CustomField insightCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(14930) // Change 23456 to the correct value
def insightObjects = issue.getCustomFieldValue(insightCustomField) // "issue" variable is always accessible in post function scripts.

/* This is the priority object type attribute and the one we want to modify */
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(379)

if (insightObjects != null) {
insightObjects.each { ObjectBean insightObject ->
def newValue = issue.getCustomFieldValue(jiraCustomField)
/* Load the attribute bean */
def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.id, objectTypeAttributeBean.id)
if (!objectAttributeBean) {
/* If attribute doesn't exist create one */
objectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, newValue[0].name)
} else {
/* If attribute exists, check if the value is not already present and add it if needed */
if(objectAttributeBean.objectAttributeValueBeans.any{it.value == newValue[0].name }) {
/* Value already present, return null to end this each iteration */
return null
}
def objectAttributeValueBean = objectAttributeBean.createObjectAttributeValueBean()
objectAttributeValueBean.setValue(objectTypeAttributeBean,newValue[0].name)
objectAttributeBean.objectAttributeValueBeans.add(objectAttributeValueBean)
}

/* Store the object attribute into Insight. */
try {
objectAttributeBean = objectFacade.storeObjectAttributeBean(objectAttributeBean)
} catch (Exception vie) {
log.warn("Could not update object attribute due to validation exception:$vie.message")
}
}
}
Marlee Pitts December 21, 2022

Unfortunately that did not work. The problem for that version is line 18:

def insightObjects = issue.getCustomFieldValue(insightCustomField) // "issue" variable is always accessible in post function scripts.

 

Message:
java.lang.NullPointerException
Stack:
com.atlassian.jira.issue.IssueImpl.getCustomFieldValue(IssueImpl.java:951)
com.atlassian.jira.issue.Issue$getCustomFieldValue.call(Unknown Source)
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
script_245f4e6aec3ad726767ce9aa19374716.run(script_245f4e6aec3ad726767ce9aa19374716.groovy:18)
PD 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.
December 21, 2022

Try this version with a bit more error trapping.

Make sure you change the 2 customfFieldId variables to match your custom fields. The script currently contains 14932 and 14930

Watch your logs while it runs and capture any details in there:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
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
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory

assert issue, "There is no 'issue' variable in the current context. Are you sure you added your script to a workflow post function?"

/* Get Insight Facades and Factories from plugin accessor */
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade)
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectTypeAttributeFacade)
def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectAttributeBeanFactory)
def customFieldManager = ComponentAccessor.customFieldManager

/* This is the custom field with the value you want to add to an object attribute */
def jiraCustomFieldId = 14932 // Change 12345 to the correct value
CustomField jiraCustomField = customFieldManager.getCustomFieldObject(jiraCustomFieldId)
assert jiraCustomField, "There is no custom field matching id: $jiraCustomFieldId"

/* This is the custom field where the object/s you want to set the value */
def insightCustomFieldId = 14930// Change 12345 to the correct value
CustomField insightCustomField = customFieldManager.getCustomFieldObject(insightCustomFieldId)
assert insightCustomField, "There is no custom field matching id: $insightCustomFieldId"
def insightObjects = issue.getCustomFieldValue(insightCustomField) // "issue" variable is always accessible in post function scripts.
if(!insightObjects){
log.warn "There are no values in $insightCustomField.name. Nothing to do here."
return
}

/* This is the priority object type attribute and the one we want to modify */
def attributeId = 379
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(attributeId)
assert objectTypeAttributeBean, "Could not load attribute with id=$attributeId. Please verify the script and make sure this is the correct attribute id"

insightObjects.each { ObjectBean insightObject ->
def newValue = issue.getCustomFieldValue(jiraCustomField)
/* Load the attribute bean */
def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.id, objectTypeAttributeBean.id)
if (!objectAttributeBean) {
/* If attribute doesn't exist create one */
objectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, newValue[0].name)
} else {
/* If attribute exists, check if the value is not already present and add it if needed */
if (objectAttributeBean.objectAttributeValueBeans.any { it.value == newValue[0].name }) {
/* Value already present, return null to end this each iteration */
return null
}
//created a version of the objectAttributeBean that can be modified
objectAttributeBean = objectAttributeBean.createMutable()
//extract the current list of values
def values = objectAttributeBean.objectAttributeValueBeans

//create a valueBean for the new entry
def objectAttributeValueBean = objectAttributeBean.createObjectAttributeValueBean()
objectAttributeValueBean.setValue(objectTypeAttributeBean, newValue[0].name)

//add the new entry to the list of values
values.add(objectAttributeValueBean)
//update the objectAttribute with the new list of values.
objectAttributeBean.setObjectAttributeValueBeans(values)
}

/* Store the object attribute into Insight. */
try {
objectAttributeBean = objectFacade.storeObjectAttributeBean(objectAttributeBean)
} catch (Exception vie) {
log.warn("Could not update object attribute due to validation exception:$vie.message")
}
}
Marlee Pitts December 21, 2022

Your script ran successfully against issue DLO-33

Result type:
ArrayList
Result value:
[User, B(DFA-2410)]
Logs:
WARN : Could not update object attribute due to validation exception:ValidationInsightException: Validation errors were found: rlabs-insight-attribute-327: ErrorMessage{i18nKey='rlabs.insight.i18n.constraint.violation.ObjectAttributeValueBean.Null.value', parameters=[], additionalMessage=null}; 
PD 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.
December 21, 2022

Here is yet another version with more logs.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
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
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory

assert issue, "There is no 'issue' variable in the current context. Are you sure you added your script to a workflow post function?"

/* Get Insight Facades and Factories from plugin accessor */
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectFacade)
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectTypeAttributeFacade)
def objectAttributeBeanFactory = ComponentAccessor.getOSGiComponentInstanceOfType(ObjectAttributeBeanFactory)
def customFieldManager = ComponentAccessor.customFieldManager

/* This is the custom field with the value you want to add to an object attribute */
def jiraCustomFieldId = 14932// Change 12345 to the correct value
CustomField jiraCustomField = customFieldManager.getCustomFieldObject(jiraCustomFieldId)
assert jiraCustomField, "There is no custom field matching id: $jiraCustomFieldId"

/* This is the custom field where the object/s you want to set the value */
def insightCustomFieldId = 14930// Change 12345 to the correct value
CustomField insightCustomField = customFieldManager.getCustomFieldObject(insightCustomFieldId)
assert insightCustomField, "There is no custom field matching id: $insightCustomFieldId"
def insightObjects = issue.getCustomFieldValue(insightCustomField) // "issue" variable is always accessible in post function scripts.
if(!insightObjects){
log.warn "There are no values in $insightCustomField.name. Nothing to do here."
return
}

/* This is the priority object type attribute and the one we want to modify */
def attributeId = 379
def objectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttributeBean(attributeId)
assert objectTypeAttributeBean, "Could not load attribute with id=$attributeId. Please verify the script and make sure this is the correct attribute id"

def newValue = issue.getCustomFieldValue(jiraCustomField)
log.info "$jiraCustomField.name value for $issue.key is $newValue (${newValue.getClass()})"
log.info "$insightCustomField.name value for $issue.key is $insightObjects"

insightObjects.each { ObjectBean insightObject ->
log.info "Processing $insightObject to see if $newValue needs to be added"
/* Load the attribute bean */
def objectAttributeBean = objectFacade.loadObjectAttributeBean(insightObject.id, objectTypeAttributeBean.id)
if (!objectAttributeBean) {
/* If attribute doesn't exist create one */
objectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(insightObject, objectTypeAttributeBean, newValue[0].name)
log.info "$objectTypeAttributeBean.name is empty for $insightObject creating a new value for ${newValue[0].name}"
} else {
/* If attribute exists, check if the value is not already present and add it if needed */
if (objectAttributeBean.objectAttributeValueBeans.any { it.value == newValue[0].name }) {
log.info "$objectTypeAttributeBean.name for $insightObject already contains ${newValue[0].name}"
/* Value already present, return null to end this each iteration */
return null
}
//created a version of the objectAttributeBean that can be modified
objectAttributeBean = objectAttributeBean.createMutable()
//extract the current list of values
def values = objectAttributeBean.objectAttributeValueBeans

//create a valueBean for the new entry
def objectAttributeValueBean = objectAttributeBean.createObjectAttributeValueBean()
objectAttributeValueBean.setValue(objectTypeAttributeBean, newValue[0].name)
log.info "Adding ${newValue[0].name} to $objectTypeAttributeBean.name for $insightObject"

//add the new entry to the list of values
values.add(objectAttributeValueBean)
//update the objectAttribute with the new list of values.
objectAttributeBean.setObjectAttributeValueBeans(values)
}

/* Store the object attribute into Insight. */
try {
objectAttributeBean = objectFacade.storeObjectAttributeBean(objectAttributeBean)
} catch (Exception vie) {
log.warn("Could not update object attribute due to validation exception:$vie.message")
}
}

Can you also provide the configuration for attribute with id = 327.

Per your error log, this attribute failed validation (but that's not the attribute we are attempting to modify -- you initially supplied attribute Id 379).

Suggest an answer

Log in or Sign up to answer