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:
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?
Functionality difference:
You can find all the code here:
Alexey Matveev
software developer
MagicButtonLabs
Philippines
1,575 accepted answers
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
17 comments