Three ways to update an issue in Jira Java Api

In this article I would like to  examine three ways to update an issue in Jira, using Jira Java API. I tested all the code, provided in this article, in Jira 7.7.0 and Adaptivist ScriptRunner 5.3.7.

I will use Issue.setCustomFieldValue, CustomField.updateValue and IssueService.update methods. I will write example scripts on how to update all out of the box custom fields, using these methods.

The following custom fields were created:

Selection_015.png

 

1. Issue.setCustomFieldValue(CustomField customField, Object value):

A sample code looks like this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Date
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.label.Label
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.user.ApplicationUser


def issue = ComponentAccessor.getIssueManager().getIssueByCurrentKey("BP-7")
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// Initialize custom fields ----------------------------------
def singleline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("singleline_field")
def datetimepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datetimepicker_field")
def checkbox_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("checkbox_field")
def number_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("number_field")
def labels_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("labels_field")
def multi_grouppicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multi_grouppicker_field")
def multiline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multiline_field")
def datepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datepicker_field")
def userpicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("userpicker_field")
def radiobuttons_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("radiobuttons_field")
def selectlist_cascading_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_cascading_field")
def select_singlechoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("select_singlechoice_field")
def selectlist_multichoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_multichoice_field")
def url_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("url_field")

// set field values -------------------------------
issue.setCustomFieldValue(singleline_field, "test 1")
issue.setCustomFieldValue(datetimepicker_field, new Date(Calendar.getInstance().getTime().getTime()))
issue.setCustomFieldValue(checkbox_field, getOptions(issue, checkbox_field, ["option 1", "option 2"]))
issue.setCustomFieldValue(number_field, (Double) 1)
issue.setCustomFieldValue(labels_field, [new Label(null, issue.getId(), labels_field.getIdAsLong(), "Label")] as Set)
issue.setCustomFieldValue(multi_grouppicker_field, [ComponentAccessor.getGroupManager().getGroup("jira-software-users")])
issue.setCustomFieldValue(multiline_field, "test 1")
issue.setCustomFieldValue(datepicker_field, new Date(Calendar.getInstance().getTime().getTime()))
issue.setCustomFieldValue(userpicker_field, findUser("admin"))
issue.setCustomFieldValue(radiobuttons_field, getOptions(issue, checkbox_field, ["option 1"]).get(0))
issue.setCustomFieldValue(selectlist_cascading_field, getCascadingOptions(issue, selectlist_cascading_field))
issue.setCustomFieldValue(select_singlechoice_field,  getOptions(issue, select_singlechoice_field, ["option 1"]).get(0))
issue.setCustomFieldValue(selectlist_multichoice_field, getOptions(issue, selectlist_multichoice_field, ["option 1", "option 2"]))
issue.setCustomFieldValue(url_field, "http://google.com")

// apply changes to Jira -----------------------
ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)

// get option list for radio button, checkbox and select custom fields
def List<Option> getOptions(Issue issue, CustomField customField, List<String> optionList) {
    def config = customField.getRelevantConfig(issue)
    def options = ComponentAccessor.getOptionsManager().getOptions(config)
    def optionsToSelect = options.findAll { it.value in optionList }
}

// get user for the user picker custom field
def ApplicationUser findUser(String userName) {
   def userSearchService = ComponentAccessor.getComponent(UserSearchService.class);
   UserSearchParams userSearchParams = (new UserSearchParams.Builder()).allowEmptyQuery(true).includeActive(true).includeInactive(true).maxResults(100000).build();

   return userSearchService.findUsers(userName, userSearchParams).get(0)

}

// get options for cascading select
def Map<String, Object> getCascadingOptions(Issue issue, CustomField customField) {
    def parentOptionObj = getOptions(issue, customField, ["option 1"]).get(0) as Option
    def childOptionObj = ComponentAccessor.getOptionsManager().findByParentId(parentOptionObj.getOptionId()).get(0)
    Map<String,Object> newValues = new HashMap<>()
    newValues.put(null, parentOptionObj)
    newValues.put("1", childOptionObj)
    return newValues
}

If you want to empty values then you should set the null value for custom fields:

issue.setCustomFieldValue(singleline_field, null) 

2. CustomField.updateValue(FieldLayoutItem fieldLayoutItem, Issue issue, ModifiedValue modifiedValue, IssueChangeHolder issueChangeHolder):

A sample code looks like this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Date
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.label.Label
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue


def issue = ComponentAccessor.getIssueManager().getIssueByCurrentKey("BP-7")
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// Initialize custom fields --------------------------
def singleline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("singleline_field")
def datetimepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datetimepicker_field")
def checkbox_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("checkbox_field")
def number_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("number_field")
def labels_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("labels_field")
def multi_grouppicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multi_grouppicker_field")
def multiline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multiline_field")
def datepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datepicker_field")
def userpicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("userpicker_field")
def radiobuttons_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("radiobuttons_field")
def selectlist_cascading_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_cascading_field")
def select_singlechoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("select_singlechoice_field")
def selectlist_multichoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_multichoice_field")
def url_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("url_field")

// set custom fields values (changes will be applied immediately) --------------------
singleline_field.updateValue(null, issue, new ModifiedValue("", (Object) "Test 1"), new DefaultIssueChangeHolder())
datetimepicker_field.updateValue(null, issue, new ModifiedValue("", (Object) new Date(Calendar.getInstance().getTime().getTime())), new DefaultIssueChangeHolder())
checkbox_field.updateValue(null, issue, new ModifiedValue("", (Object) getOptions(issue, checkbox_field, ["option 1", "option 2"])), new DefaultIssueChangeHolder())
number_field.updateValue(null, issue, new ModifiedValue("",  (Object) (Double)  1), new DefaultIssueChangeHolder())
labels_field.updateValue(null, issue, new ModifiedValue("",  (Object) ([new Label(null, issue.getId(), labels_field.getIdAsLong(), "Label")] as Set)), new DefaultIssueChangeHolder())
multi_grouppicker_field.updateValue(null, issue, new ModifiedValue("",  (Object) [ComponentAccessor.getGroupManager().getGroup("jira-software-users")]), new DefaultIssueChangeHolder())
multiline_field.updateValue(null, issue, new ModifiedValue("",  (Object)  "test 1"), new DefaultIssueChangeHolder())
datepicker_field.updateValue(null, issue, new ModifiedValue("",  (Object)  new Date(Calendar.getInstance().getTime().getTime())), new DefaultIssueChangeHolder())
userpicker_field.updateValue(null, issue, new ModifiedValue("",  (Object) findUser("admin")), new DefaultIssueChangeHolder())
radiobuttons_field.updateValue(null, issue, new ModifiedValue("",  (Object) getOptions(issue, checkbox_field, ["option 1"]).get(0)), new DefaultIssueChangeHolder())
selectlist_cascading_field.updateValue(null, issue, new ModifiedValue("",  (Object)  getCascadingOptions(issue, selectlist_cascading_field)), new DefaultIssueChangeHolder())
select_singlechoice_field.updateValue(null, issue, new ModifiedValue("",  (Object) getOptions(issue, select_singlechoice_field, ["option 1"]).get(0)), new DefaultIssueChangeHolder())
selectlist_multichoice_field.updateValue(null, issue, new ModifiedValue("",  (Object) getOptions(issue, selectlist_multichoice_field, ["option 1", "option 2"])), new DefaultIssueChangeHolder())
url_field.updateValue(null, issue, new ModifiedValue("",  (Object) "http://google.com"), new DefaultIssueChangeHolder())

// all functions are the same as in the script above ---------------------

 You can empty custom fields by setting the null value:

singleline_field.updateValue(null, issue, new ModifiedValue("", null), new DefaultIssueChangeHolder())

3.  IssueService.update(ApplicationUser user, IssueService.UpdateValidationResult updateValidationResult):

A sample code looks like this:

import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.UpdateValidationResult
import com.atlassian.jira.bc.issue.IssueService.IssueResult
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.label.Label
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.user.ApplicationUser
import java.text.SimpleDateFormat

def issue = ComponentAccessor.getIssueManager().getIssueByCurrentKey("BP-7")
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// initialize custom fields --------------------
def singleline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("singleline_field")
def datetimepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datetimepicker_field")
def checkbox_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("checkbox_field")
def number_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("number_field")
def labels_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("labels_field")
def multi_grouppicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multi_grouppicker_field")
def multiline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("multiline_field")
def datepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("datepicker_field")
def userpicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("userpicker_field")
def radiobuttons_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("radiobuttons_field")
def selectlist_cascading_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_cascading_field")
def select_singlechoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("select_singlechoice_field")
def selectlist_multichoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("selectlist_multichoice_field")
def url_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("url_field")

IssueService issueService = ComponentAccessor.getComponent(IssueService.class);
IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
// set values for custom fields ------------------
issueInputParameters
      .addCustomFieldValue(singleline_field.getId(), "Test 1")
      .addCustomFieldValue(datetimepicker_field.getId(), new SimpleDateFormat("d/MMM/yy hh:mm a").format(new Date()))
      .addCustomFieldValue(checkbox_field.getId(),  getOptionsAsString(issue, checkbox_field, ["option 1"]))
      .addCustomFieldValue(number_field.getId(), "1")
      .addCustomFieldValue(labels_field.getId(), "Label")
      .addCustomFieldValue(multi_grouppicker_field.getId(), "jira-software-users")
      .addCustomFieldValue(multiline_field.getId(), "Test 2")
      .addCustomFieldValue(datepicker_field.getId(), new SimpleDateFormat("d/MMM/yy").format(new Date()))
      .addCustomFieldValue(userpicker_field.getId(), "admin")
      .addCustomFieldValue(radiobuttons_field.getId(), getOptionsAsString(issue, radiobuttons_field, ["option 1"]))
      .addCustomFieldValue(selectlist_cascading_field.getId(), getCascadingOptions(issue, selectlist_cascading_field).get("parent").toString())
      .addCustomFieldValue(selectlist_cascading_field.getId() + ":1", getCascadingOptions(issue, selectlist_cascading_field).get("1").toString())
      .addCustomFieldValue(select_singlechoice_field.getId(), getOptionsAsString(issue, select_singlechoice_field, ["option 1"]))
      .addCustomFieldValue(selectlist_multichoice_field.getId(), getOptionsAsString(issue, selectlist_multichoice_field, ["option 1"]))
      .addCustomFieldValue(url_field.getId(), "http://google.com")
// we do not provide all the values for an issue, that is why we need to state it
      issueInputParameters.setRetainExistingValuesWhenParameterNotProvided(true,true)
// validate update -------------
UpdateValidationResult updateValidationResult = issueService.validateUpdate(user, issue.getId(), issueInputParameters);
if (updateValidationResult.isValid())
{
// update the issue ----------
    IssueResult updateResult = issueService.update(user, updateValidationResult);
    if (!updateResult.isValid())
    {
        log.error("error updateResult: " + updateResult.getErrorCollection().toString())
    }
} else {
    log.error("error: updateValidationResult" + updateValidationResult.getErrorCollection().toString())
}

// get options for radio button, checkbox and select custom fields ------
def List<Option> getOptions(Issue issue, CustomField customField, List<String> optionList) {
    def config = customField.getRelevantConfig(issue)
    def options = ComponentAccessor.getOptionsManager().getOptions(config)
    return options.findAll{ it.value in optionList }
}
// represent options as String
def String getOptionsAsString(Issue issue, CustomField customField, List<String> optionList) {
    List<Long> optionIdList = new ArrayList<>()
    getOptions(issue, customField, optionList).each {
       optionIdList.add(((Option) it).getOptionId())
    }
    return optionIdList.join(",")

}

// get user for user picker custom field
def ApplicationUser findUser(String userName) {
   def userSearchService = ComponentAccessor.getComponent(UserSearchService.class);
   UserSearchParams userSearchParams = (new UserSearchParams.Builder()).allowEmptyQuery(true).includeActive(true).includeInactive(true).maxResults(100000).build();

   return userSearchService.findUsers(userName, userSearchParams).get(0)

}
// get cascading options
def Map<String, Object> getCascadingOptions(Issue issue, CustomField customField) {
    def parentOptionObj = getOptions(issue, customField, ["option 1"]).get(0) as Option
    def childOptionObj = ComponentAccessor.getOptionsManager().findByParentId(parentOptionObj.getOptionId()).get(0)
    Map<String,Object> newValues = new HashMap<>()
    newValues.put("parent", parentOptionObj.getOptionId())
    newValues.put("1", childOptionObj.getOptionId())
    return newValues
}

 You can empty field by:

 .addCustomFieldValue(singleline_field.getId(), null)

 What type of values to pass to the three methods?

Selection_016.png 

 Functionality difference:

 Selection_017.png

 You can find all the code here:

Issue.setCustomFieldValue

CustomField.updateValue

IssueService.update

17 comments

Gonchik Tsymzhitov
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
February 25, 2018

 

Thank you Alexey for the overview. 

Actually, functionality difference table will decrease my work for small customizes.

 

Cheers,

Gonchik Tsymzhitov

Mahesh S
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.
March 1, 2018

Thanks! A very useful write up! Its something which I have tried understanding in the past and walked towards other methods.

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
March 3, 2018

A question that I've been asked (and never had a good answer for) - which methods work best where?

By "where", I mean where the code is run.  For example, a post-function on issue create is different to a post-function everywhere else in the workflow, and both are different to listeners.

Steve Thornhill
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.
March 4, 2018

Thank you for a very useful article.

Abhishek Sharma April 25, 2018

Thank you Alexey for such a great write up on this. I have struggling on this for a week now & was unable to decide on which method to use. Your write up indeed gave me a direction to to work.

I'm using the updateValue() function to update value into a custom field. But I'm getting a method invocation error. I'm sharing the error trace for reference. Pls. lemme know if anybody can help me get past this exception:

*****************************************************************************************
Sourced file: inline evaluation of: `` import com.atlassian.jira.issue.Issue; import com.atlassian.jira.issue.Modifi . . . '' : Error in method invocation: Method updateValue( com.atlassian.jira.issue.fields.layout.field.FieldLayoutItemImpl, com.innovalog.jmcf.fields.IssueProxy, com.atlassian.jira.issue.ModifiedValue, com.atlassian.jira.issue.util.DefaultIssueChangeHolder ) not found in class'com.atlassian.jira.issue.fields.ImmutableCustomField' : at Line: 28 : in file: inline evaluation of: 

*****************************************************************************************

Just not sure why it's going to ImmutableCustomField :(

 

Appreciate all your help in advance.

Thanks,

Abhi

Leirbag Assuab June 6, 2018

Thanks for a very useful article.

A simple reflexion for beginners like me:

When using ...

issueService.update(user, updateValidationResult)

...in a listener class, one must decide if we want another event to be launched or not, then use overloaded method:

update(ApplicationUser user, IssueService.UpdateValidationResult updateValidationResult, EventDispatchOption eventDispatchOption, boolean sendMail)
admin_site January 17, 2019

how to do the same with JRJC ?

Ken Lucio March 13, 2019

Valuable knowledge. Thank you!

Eugene Ts November 11, 2019

Thanks for the article.

Does anybody know how to update those field from implementing a custom Jira server plugin? I need to have this logic, but without using ScriptRunner (customer's wishes).

Thanks in advance!

Regards,

Eugene

Leirbag Assuab November 12, 2019

Hi @Eugene Ts!

Do you mean you are writing a java add-on for Jira Server and need to update some issue fields? In that case, you can easily convert this code from Groovy to Java. Note that packages names, classes, methods,... are the same in both languages. You also have to set variables to their correct classes, but it's so easy by looking at type returned by methods. Closures are the hard part from my point of view, but it's quite intuitive when you understand what the code is intending to do.

Here it is method "3 IssueService.update" above, converted by myself to Java. Surely it can be improved, I'm not a master of Java. And this proves you also can do it... ;-)

package com.mycompany.jira.myplugin;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.atlassian.jira.bc.issue.IssueService;
import com.atlassian.jira.bc.issue.IssueService.IssueResult;
import com.atlassian.jira.bc.issue.IssueService.UpdateValidationResult;
import com.atlassian.jira.bc.user.search.UserSearchParams;
import com.atlassian.jira.bc.user.search.UserSearchService;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueInputParameters;
import com.atlassian.jira.issue.customfields.option.Option;
import com.atlassian.jira.issue.customfields.option.Options;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.fields.config.FieldConfig;
import com.atlassian.jira.user.ApplicationUser;

public class sample {

private static final Logger log = LoggerFactory.getLogger(sample.class);

public void doSomething() {

Issue issue = ComponentAccessor.getIssueManager().getIssueByCurrentKey("BP-7");
ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();

// initialize custom fields --------------------
CustomField singleline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("singleline_field");
CustomField datetimepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("datetimepicker_field");
CustomField checkbox_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("checkbox_field");
CustomField number_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("number_field");
CustomField labels_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("labels_field");
CustomField multi_grouppicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("multi_grouppicker_field");
CustomField multiline_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("multiline_field");
CustomField datepicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("datepicker_field");
CustomField userpicker_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("userpicker_field");
CustomField radiobuttons_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("radiobuttons_field");
CustomField selectlist_cascading_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("selectlist_cascading_field");
CustomField select_singlechoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("select_singlechoice_field");
CustomField selectlist_multichoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("selectlist_multichoice_field");
CustomField url_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("url_field");

IssueService issueService = ComponentAccessor.getComponent(IssueService.class);
IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
// set values for custom fields ------------------
issueInputParameters
.addCustomFieldValue(singleline_field.getId(), "Test 1")
.addCustomFieldValue(datetimepicker_field.getId(), new SimpleDateFormat("d/MMM/yy hh:mm a").format(new Date()))
.addCustomFieldValue(checkbox_field.getId(), getOptionsAsString(issue, checkbox_field, Arrays.asList("option1")))
.addCustomFieldValue(number_field.getId(), "1")
.addCustomFieldValue(labels_field.getId(), "Label")
.addCustomFieldValue(multi_grouppicker_field.getId(), "jira-software-users")
.addCustomFieldValue(multiline_field.getId(), "Test 2")
.addCustomFieldValue(datepicker_field.getId(), new SimpleDateFormat("d/MMM/yy").format(new Date()))
.addCustomFieldValue(userpicker_field.getId(), "admin")
.addCustomFieldValue(radiobuttons_field.getId(), getOptionsAsString(issue, radiobuttons_field, Arrays.asList("option1")))
.addCustomFieldValue(selectlist_cascading_field.getId(), getCascadingOptions(issue, selectlist_cascading_field).get("parent").toString())
.addCustomFieldValue(selectlist_cascading_field.getId() + ":1", getCascadingOptions(issue, selectlist_cascading_field).get("1").toString())
.addCustomFieldValue(select_singlechoice_field.getId(), getOptionsAsString(issue, select_singlechoice_field, Arrays.asList("option1")))
.addCustomFieldValue(selectlist_multichoice_field.getId(), getOptionsAsString(issue, selectlist_multichoice_field, Arrays.asList("option1")))
.addCustomFieldValue(url_field.getId(), "http://google.com");
// we do not provide all the values for an issue, that is why we need to state it
issueInputParameters.setRetainExistingValuesWhenParameterNotProvided(true,true);
// validate update -------------
UpdateValidationResult updateValidationResult = issueService.validateUpdate(user, issue.getId(), issueInputParameters);
if (updateValidationResult.isValid())
{
// update the issue ----------
IssueResult updateResult = issueService.update(user, updateValidationResult);
if (!updateResult.isValid());
{
log.error("error updateResult: " + updateResult.getErrorCollection().toString());
}
} else {
log.error("error: updateValidationResult" + updateValidationResult.getErrorCollection().toString());
}

}


// get options for radio button, checkbox and select custom fields ------
private List<Option> getOptions(Issue issue, CustomField customField, List<String> optionList) {
FieldConfig config = customField.getRelevantConfig(issue);
Options options = ComponentAccessor.getOptionsManager().getOptions(config);
//return options.findAll{ it.value in optionList }
List<Option> listOptions = new ArrayList<Option>();
options.forEach(item->{
if(optionList.contains(item.getValue()) ){
listOptions.add(item);
}
});

return listOptions;
}

// represent options as String
private String getOptionsAsString(Issue issue, CustomField customField, List<String> optionList) {
List<String> optionIdList = new ArrayList<>();
getOptions(issue, customField, optionList).forEach( it->{
optionIdList.add(((Option) it).getOptionId().toString());
});

return String.join(",", optionIdList);
}

// get user for user picker custom field
private ApplicationUser findUser(String userName) {
UserSearchService userSearchService = ComponentAccessor.getComponent(UserSearchService.class);
UserSearchParams userSearchParams = (new UserSearchParams.Builder()).allowEmptyQuery(true).includeActive(true).includeInactive(true).maxResults(100000).build();

return userSearchService.findUsers(userName, userSearchParams).get(0);
}

// get cascading options
private Map<String, Object> getCascadingOptions(Issue issue, CustomField customField) {
Option parentOptionObj = getOptions(issue, customField, Arrays.asList("option1")).get(0);
Option childOptionObj = ComponentAccessor.getOptionsManager().findByParentId(parentOptionObj.getOptionId()).get(0);
Map<String,Object> newValues = new HashMap<String,Object>();
newValues.put("parent", parentOptionObj.getOptionId());
newValues.put("1", childOptionObj.getOptionId());
return newValues;
}

}

Hope it helps you.

Like Eugene Ts likes this
Sibi_K March 1, 2020

Hi all,

 

i am struck with how to get and update the single issue and multi issue picker that is missing in this post. Any help is much appriciated 

 

Thanks,

Sibi

Like Vladislav likes this
Vladislav July 1, 2020

Hi Sibi,

Did you find a solution?

I'm struggling on  this as well.

Thanks in advance!

Pavel Kapinos July 9, 2020

Info about IssueService.update is not correct.

issueInputParameters.setSkipScreenCheck(true)
issueInputParameters.setSkipLicenceCheck(true)
issueInputParameters.setRetainExistingValuesWhenParameterNotProvided(true, true)

 There are three parameters allowed to ignore permission and edit rules

Mamikon Papikyan January 11, 2021

Hi Alexey,

Thanks it's working perfectly in the jira version 7.x. But not working in version 8.x, when I set custom field values, and after that getting values are null. Also the new values displayed on the issue, but programmatically those are null. Why?

Thanks,

Mamikon

mark.lamport March 16, 2021

I have an issue where I update a customField for an Epic when opening an Epic (calls a custom script and runs Groovy code) and  uses UpdateValue of  an Issue.  However in JIRA roadmaps it doesnt get updated unless I edit a text field and click Review.  Has anyone come across this issue before?

 

Sample Groovy code below:

 

CustomField scoreCF = customFieldManager.getCustomFieldObjectsByName(ScoreCustomField).first()
if (scoreCF != null) {
// We write the score
def scoreCFValue = czIssue.getCustomFieldValue(scoreCF)
scoreCF.updateValue(null, czIssue, new ModifiedValue(scoreCFValue, score.toDouble()), changeHolder)
}

 

When going into JIRA roadmaps and refreshing, this customField is not updated.  Am I missing something?

 

I appreciate any help in this.

 

Thanks,

 

-Mark

Like Anar Mahmudzada likes this
Anar Mahmudzada May 31, 2022

Hi Alexey,

Many thanks for this amazing and most ever helpful post. I really appreciate your help. This is the first time that I saw so efficient and helpful post in this postal. God save and bless you. Perhaps you do not know it, but be sure you saved my life. I am really thankful to you.

 

Kind regards,

Anar

Majo Francis July 23, 2022

Thank you @Alexey for this.. I am so late to discover this page.. 

@leirbag Thank you for the Java Code as well. I tried it and works fine for most of the fields. However it doesn't work for selecting multiple options in Check Box field, Multi Select field etc. Code is able to update single values in these fields though.

 

I have made some slight modifications and now it works fine for selecting multiple options as well..

 

Basically a comma separated list of option Ids (Eg: "30001, 30002"  )does not seems to work, it takes a String array of Ids ( Eg : ["30001", "30002"] )

 

CustomField selectlist_multichoice_field = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("selectlist_multichoice_field");

// These are the field values to be selected.
String fieldValues = "Option 1, Option 3";

// fieldValues.split("\\s*,\\s*") --> Splits the String based on ',' and gives a String [].

issueInputParameters.addCustomFieldValue(selectlist_multichoice_field.getId(), getOptionsAsString(issue, selectlist_multichoice_field, Arrays.asList(fieldValues.split("\\s*,\\s*")));


private String[] getOptionsAsString(Issue issue, CustomField customField, List<String> optionList) {
List<String> optionIdList = new ArrayList<>();
getOptionsList(issue, customField, optionList).forEach(it -> {
optionIdList.add(((Option) it).getOptionId().toString());
});

// addCustomFieldValue() expects String []
return optionIdList.toArray(new String[0]);
}

private List<Option> getOptionsList(Issue issue, CustomField customField, List<String> optionList) {
FieldConfig config = customField.getRelevantConfig(issue);
Options options = ComponentAccessor.getOptionsManager().getOptions(config);

List<Option> listOptions = new ArrayList<Option>();
options.forEach(item -> {
if (optionList.contains(item.getValue())) { 
listOptions.add(item);
}
});


NB : This code may/may not be performance efficient... 

Like Srikanth Ganipisetty likes this
TAGS
AUG Leaders

Atlassian Community Events