Apps documentation
Extension for Jira Service Management
Cloud Server/Data Center
Extension for Jira Service Management

Cloud

Server/Data Center

Documentation
FAQ
Release notes
Articles & Videos
Last updated Jan 9, 2024

Java API (ScriptRunner)

Learn how to use data from Bundled Fields in ScriptRunner

Extension for Jira Service Management allows you to use data from Bundled Fields in ScriptRunner, or any other similar app. You’ll find all possible actions that you can perform this way in the right-hand side navigation menu.

Our API methods are public services that can be used in any code editor. The examples, however, are prepared to match the ScriptRunner’s format in particular. If you’d like to use the methods in other applications, you will need to adjust the code according to their requirements.

We’ve tested all methods in this chapter and made sure that they work in the form provided in the examples. Nevertheless, the support we provide doesn’t include verifying custom scripts. In case of any issues with customized code, we recommend checking out the ScriptRunner documentation, too.

Info
  • Currently we don’t support ScriptRunner’s Behaviours.
  • To investigate any problems with scripts using Bundled Fields’ API, go to Troubleshooting.
  • To see an example of a Bundled Fields’ JSON structure and descriptions of the attributes, go to Examples and definitions.
Note

Before you start, make sure that the Bundled Fields custom field is added to the Edit screen in your workflow. Otherwise, the scripts might not work.

Get bundled field

Get an object representing a bundled field for the given issue object or issue key and the bundled field’s ID.

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

Get bundled field draft

Build an object representing a draft of a bundled field for the given issue object or issue key and the bundled field’s ID:

Tip

Bundled field draft objects allow you to make multiple changes (one by one) on a single bundled field object. You can find the list of all available methods that interact with drafts in the List of available signatures and SaveableBundledField below. After all changes are made on a bundled field, commit them by calling the save function.

def bundledFieldDraft = bundledFieldService.getBundledFieldDraft(issueOrKey, bundledFieldId)

You can make changes by using:

bundledFieldDraft.setSubfieldValue("Subfield name 1", "Value in every Subfield name 1 in all groups");
bundledFieldDraft.setSubfieldValue("Subfield name 2", "Value in every Subfield name 2 in all groups");
bundledFieldDraft.setSubfieldValue("Subfield name 1", "Value in Subfield name 1 in first group", 0);

You need to save to apply changes:

bundledFieldDraft.save()

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.deviniti.plugins.bundledfields.api.issue.BundledFieldService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.deviniti.plugins.bundledfields.api.issue.Subfield

String issueOrKey = 'TEST-38'
String bundledFieldId = "customfield_12000"

@WithPlugin("com.intenso.jira.plugin.jsd-extender")
@PluginModule
BundledFieldService bundledFieldService;

def bundledFieldDraft = bundledFieldService.getBundledFieldDraft(issueOrKey, bundledFieldId);
bundledFieldDraft.setSubfieldValue("Subfield name 1", "Value in every Subfield name 1 in all groups");
bundledFieldDraft.setSubfieldValue("Subfield name 2", "Value in every Subfield name 2 in all groups");
bundledFieldDraft.setSubfieldValue("Subfield name 1", "Value in Subfield name 1 in first group", 0);

bundledFieldDraft.save();

Get subfield

Get a subfield object for the given name and group index.

def subField = bundledField.getSubfield("Name", 0)
Note

Groups numbering starts from 0.

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

def subField = bundledField.getSubfield("Name", 0)
Tip

You can also retrieve a subfield by its originId. Learn more

Get group by index

Get a group object using index.

def group = bundledField.getGroup(0)
Note

Rows numbering starts from 0.

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

def group = bundledField.getGroup(0)

Get all groups of a field

Get a list of all groups of a bundled field.

def groups = bundledField.getGroups()

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

def groups = bundledField.getGroups()

Add new group with subfields

Add a new group containing subfields from the list defined above. Either the value and originId, or the name will be recognized.

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

def newGroupFields = [
    Subfield.builder()
        .originId("7a23604a-c78a-4a54-b5ff-9f92175ba7a7")
        .value("John")
        .build(),
    Subfield.builder()
        .name("Date of arrival")
        .value(new Date())
        .build(),
    Subfield.builder()
        .originId("f9ad017e-df32-4b7a-8120-ef1e9e8fff36")
        .value(['fdd8d043-f13b-4d71-8ea3-1f838e7c178b'])
        .build()
]

bundledField.addGroup(newGroupFields)

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

def newGroupFields = [
    Subfield.builder()
        .originId("7a23604a-c78a-4a54-b5ff-9f92175ba7a7")
        .value("John")
        .build(),
    Subfield.builder()
        .name("Date of arrival")
        .value(new Date())
        .build(),
    Subfield.builder()
        .originId("f9ad017e-df32-4b7a-8120-ef1e9e8fff36")
        .value(['fdd8d043-f13b-4d71-8ea3-1f838e7c178b'])
        .build()
]

bundledField.addGroup(newGroupFields)

Override - copy field value

This method overrides fields on which it is used and generates new group/subfield identifiers.

Subfields that receive no value from the source field are cleared. A field needs to have the same name or be mapped to receive a value.

Exceptions:

  • A source field has a different number of groups (min/max groups)
  • A designated subfield is required and won’t receive a value (or the value will be empty)
  • Invalid value type

There are two options:

  • Search for names (a field that you want to copy must have the same subfield names)
targetBF.override(sourceBF)
  • Transfer name or originId subfield mapping (can be useful when subfield names are different, in this case you can connect two subfields so the mechanism knows which subfield should be considered in terms of value).
def subfieldMappings = [
    "date time picker subfield": "date time 2",
    "385dffb9-6d11-433d-9a97-4cc72200e3e7": "4785ef1c-04e5-4d55-bf6e-c7dae781af31"
]
targetBF.override(sourceBF, subfieldMappings);
targetBF.save()
Example
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String sourceIssueKey = 'DF-2'
String targetIssueKey = 'TEST-14'
String bundledFieldId= "customfield_10500"

def sourceBF = extensionBundledService.getBundledFieldDraft(sourceIssueKey, bundledFieldId)
def targetBF = extensionBundledService.getBundledFieldDraft(targetIssueKey, bundledFieldId)

targetBF.override(sourceBF);
targetBF.save()

Remove group by parameter

Remove a group of the given parameter.

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

bundledField.removeGroup(group)

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

def group = bundledField.getGroup(0)

bundledField.removeGroup(group)

Remove group by index

Remove a group of the given index.

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

bundledField.removeGroup(2)
Note

Rows numbering starts from 0.

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.removeGroup(2)

Remove first group

Remove the first group - respectively to removeGroup(0).

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

bundledField.removeFirstGroup()

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.removeFirstGroup()
String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.removeFirstGroup()

Remove last group

Remove the first group - respectively to removeGroup(bundledField.getGroups().size() - 1)

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

bundledField.removeLastGroup()

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.removeLastGroup()

Example of retrieving values from selected options, using select and checkbox subfields

Here’s how to get subfield values from the first group in an issue with two groups and two subfields.

Exemplary Bundled Fields’ configuration

Jira Service Management Dynamic Forms - Bundled Fields Java API
Jira Service Management Dynamic Forms - Bundled Fields Java API
Jira Service Management Dynamic Forms - Bundled Fields Java API
Jira Service Management Dynamic Forms - Bundled Fields Java API

Exemplary script for getting subfield values in the first group

import com.deviniti.plugins.bundledfields.api.issue.BundledField
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.deviniti.plugins.bundledfields.api.issue.CheckboxField
import com.deviniti.plugins.bundledfields.api.issue.SelectField
import com.deviniti.plugins.bundledfields.api.issue.Option
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import org.apache.log4j.Logger
import org.apache.log4j.Level

log.setLevel(Level.DEBUG)

String ISSUE_OR_KEY = "DFT-67";
String EXT_BF_CUSTOM_FIELD_ID = "customfield_15500";
int FIRST_GROUP = 0;

@WithPlugin("com.intenso.jira.plugins.jsd-extender")
@PluginModule
ExtensionBundledService extensionBundledService

BundledField ext_bf = extensionBundledService.getBundledField(ISSUE_OR_KEY, EXT_BF_CUSTOM_FIELD_ID);

String selectFieldName = "Select Field 1";
def selectField1 = ext_bf.getSubfield(selectFieldName, FIRST_GROUP)
if (selectField1 instanceof SelectField) {
    Option selectedOption = selectField1.getSelectedOption()
    log.debug("Value of \""+selectFieldName+"\" in group " + FIRST_GROUP + ":")
    log.debug("Id: " + selectedOption.getId())
  	log.debug("Name: " + selectedOption.getName())
}

log.debug("---------")

String checkboxFieldName = "Checkbox Field 1";
def checkboxField1 = ext_bf.getSubfield(checkboxFieldName, FIRST_GROUP)
if (checkboxField1 instanceof CheckboxField) {
    List<Option> selectedOptions = checkboxField1.getSelectedOptions();
    log.debug("Values of \""+checkboxFieldName+"\" in group " + FIRST_GROUP + ":")
    for(selectedOption in selectedOptions){
        log.debug("Id: " + selectedOption.getId())
        log.debug("Name: " + selectedOption.getName())
    }
}

Output

2022-01-13 13:56:05,096 DEBUG [runner.ScriptBindingsManager]: Value of "Select Field 1" in group 0:
2022-01-13 13:56:05,096 DEBUG [runner.ScriptBindingsManager]: Id: 0ec8f0ce-1ee5-4a50-90f5-0e459efa5fb7
2022-01-13 13:56:05,096 DEBUG [runner.ScriptBindingsManager]: Name: One
2022-01-13 13:56:05,096 DEBUG [runner.ScriptBindingsManager]: ---------
2022-01-13 13:56:05,098 DEBUG [runner.ScriptBindingsManager]: Values of "Checkbox Field 1" in group 0:
2022-01-13 13:56:05,098 DEBUG [runner.ScriptBindingsManager]: Id: 09f2a202-028b-4b32-a832-98e6786bce4b
2022-01-13 13:56:05,098 DEBUG [runner.ScriptBindingsManager]: Name: One
2022-01-13 13:56:05,098 DEBUG [runner.ScriptBindingsManager]: Id: 418270b4-f965-4e3f-bff0-308b54f721bb
2022-01-13 13:56:05,098 DEBUG [runner.ScriptBindingsManager]: Name: Two

Set subfield value in all groups

Set a value for a subfield in all groups (without defining the index).

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

Note

Type of the value must be compatible with the configured field’s type.

bundledField.setSubfieldValue("Name", "Jane Doe")

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.setSubfieldValue("Name", "Jane Doe")

Set subfield value in a group

Set a value for a subfield in a group (with a defined index).

If you want to perform this type of action on the bundledField object more than once, consider using the draft method.

bundledField.setSubfieldValue("Name", "Jane Doe", 2)

Example

import com.atlassian.jira.component.ComponentAccessor
import groovy.json.JsonSlurper
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = 'TEST-38'
String bundledFieldId= "customfield_12000"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

bundledField.setSubfieldValue("Name", "Jane Doe", 2)

List of available signatures

BundledFieldService

BundledField getBundledField(String issueOrKey, String customFieldId);
BundledField getBundledField(Issue issue, String customFieldId);
SaveableBundledField getBundledFieldDraft(String issueOrKey, String customFieldId);
SaveableBundledField getBundledFieldDraft(Issue issue, String customFieldId);

BundledField

If you want to perform below methods on the bundled field object more than once, consider using the SaveableBundledField type.

Subfield getSubfield(String name, int groupIndex)
Group getGroup(int groupIndex)
List<Group> getGroups()
void setSubfieldValue(String name, Object value)
void setSubfieldValue(String name, Object value, int groupIndex)
void addGroup(List<Subfield> fields)
void removeGroup(int groupIndex)
void removeGroup(Group group)
void removeFirstGroup()
void removeLastGroup()

SaveableBundledField

You can find here a list of methods designed to make multiple changes (one by one) to a single bundled field object. After all changes are made on a bundled field, commit them by calling the save function.

Subfield getSubfield(String name, int groupIndex)
Group getGroup(int groupIndex)
List<Group> getGroups()
void setSubfieldValue(String name, Object value)
void setSubfieldValue(String name, Object value, int groupIndex)
void addGroup(List<Subfield> fields)
void removeGroup(int groupIndex)
void removeGroup(Group group)
void removeFirstGroup()
void removeLastGroup()
void save()

Group

String getId()
List<Subfield> getFields()

Subfield

String getId()
String getOriginId()
Object getValue()
String getName()
String getType()

Correct values for each type

Subfield type Supported data type Additional conditions
TEXT String Maximum length 255 characters. Value should be compatible with a regular expression, mask, or set formatting (for example, number for the Currency type).
TEXTAREA String
USER String Contains a key of a user existing in Jira
SELECT String Contains ID/Name of the configured option.
CHECKBOX Iterable Collection of IDs/Names of the configured options.
DATE Date
DATETIME Date
TIME Date
Tip

Use a null or an empty string to clear the value.

Validation

ScriptRunner Validation is possible with a method overloading script within the BundledFieldService. It allows you to use a specific object from a postfunction (or validation) that’s being executed during transition.

BundledField getBundledField(Issue issue, String customFieldId)

Example

Here’s an example of validating a certain word as forbidden.

Script

Dynamic Forms for Jira - Bundled Fields Java API: Validation Script
Dynamic Forms for Jira - Bundled Fields Java API: Validation Script

Result

Dynamic Forms for Jira - Bundled Fields Java API: Validation result
Dynamic Forms for Jira - Bundled Fields Java API: Validation result
Note

The ScriptRunner postfunction must be placed below the “Update change history for an issue and store the issue in the database” step:

Dynamic Forms for Jira - Bundled Fields Java API: ScriptRunner postfunction's order
Dynamic Forms for Jira - Bundled Fields Java API: ScriptRunner postfunction's order

Otherwise, the value you’ve defined in the script will be overwritten by the value from the screen assigned to the transition.

Tip: Removing the field from the screen solves this problem, too.

Classes representing subfield types

All classes listed in the below table inherit from the Subfield object and get retrieved by the BundledField object’s methods, depending on their type.

derived class subfield’s type path methods defined in the class
CheckboxField checkbox import com.deviniti.plugins.bundledfields.api.issue.CheckboxField List<Option> getSelectedOptions
SelectField select import com.deviniti.plugins.bundledfields.api.issue.SelectField Option getSelectedOption
DateField date, datetime, time import com.deviniti.plugins.bundledfields.api.issue.DateField
TextField textarea, text import com.deviniti.plugins.bundledfields.api.issue.TextField
UserField user import com.deviniti.plugins.bundledfields.api.issue.UserField

Example of using the returned SelectField type

import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.deviniti.plugins.bundledfields.api.issue.Subfield
import com.deviniti.plugins.bundledfields.api.issue.CheckboxField
import com.deviniti.plugins.bundledfields.api.issue.SelectField
import com.deviniti.plugins.bundledfields.api.issue.Option
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String issueOrKey = "TEST-1"
String bundledFieldId= "customfield_10200"

def bundledField = extensionBundledService.getBundledField(issueOrKey, bundledFieldId)

Subfield subField = bundledField.getSubfield("select", 0)

if (subField instanceof SelectField) {
Option selectedOption = subField.getSelectedOption()
log.info(selectedOption.getName())
}

Methods available in the returned Option object

String getId()
String getName()

SubfieldUtils Class

This class contains additional methods for checking the type of a Subfield object and casting it to a specific derived class. If the subfield is of a different type than the one listed in the table in the first section, the following exception is thrown: SubfieldClassCastException to inform about the conflict: %s subfield cannot be cast to %s subfield.

SubfieldUtils path

import com.deviniti.plugins.bundledfields.api.issue.utils.SubfieldUtils;

SubfieldUtils methods

boolean isCheckbox(Subfield subfield)
boolean isSelect(Subfield subfield)
boolean isDate(Subfield subfield)
boolean isText(Subfield subfield)
boolean isUser(Subfield subfield)

CheckboxField toCheckboxField(Subfield subfield)
SelectField toSelectField(Subfield subfield)
DateField toDateField(Subfield subfield)
TextField toTextField(Subfield subfield)
UserField toUserField(Subfield subfield)

Implementation of the toString method in classes: Group, Subfield, and Option

When you type any of the above mentioned objects into the console you will be able to immediately see all the information it contains, for example:

Group(id=baseGroupId, fields=[TextField(super=Subfield(id=b0603214-7ab4-4880-9a9a-ba14d3c26156, originId=b0603214-7ab4-4880-9a9a-ba14d3c26156, value=Some value, name=text field, type=text)), SelectField(super=Subfield(id=740bf7fc-1f6e-475e-93a0-986f0f4ebb4e, originId=740bf7fc-1f6e-475e-93a0-986f0f4ebb4e, value=[6a559b54-7821-40f8-bb11-ce78d0ee8f19], name=select, type=select), selectedOption=Option(id=6a559b54-7821-40f8-bb11-ce78d0ee8f19, name=s2))])

Retrieving a field by originId

In most cases, retrieving a field by its name will be enough but we also provide the possibility to retrieve a field by its originId when using the getSubfield and setSubfieldValue methods.

Differences between ID and originId

Please note that the originId of a subfield differs from its ID. Here are the definitions:

  • originId – indicator of a subfield existing in the configuration as its identifier
  • ID – is an identifier of a subfield within the Bundled Fields custom field (unique across all groups)

How to find originId

There is a number of places you can get the originId from:

  • ScriptRunner console. You’ll see the originId in the Result tab after retrieving a group:
    Dynamic Forms for Jira - Bundled Fields Java API: Getting the originId from the ScriptRunner console
    Dynamic Forms for Jira - Bundled Fields Java API: Getting the originId from the ScriptRunner console
  • Database. You’ll find the originId in the AO_2AE210_JSD_BUNDLED_FIELD table. Navigate to the FIELD_ID column and select a specific record based on the customfield’s ID and its context.
  • Developer console in browser (Jira issue view, edit issue screen, or configuration screen):
    Dynamic Forms for Jira - Bundled Fields Java API: Getting the originId from the Developer console in browser
    Dynamic Forms for Jira - Bundled Fields Java API: Getting the originId from the Developer console in browser

Cases that throw exceptions

  • Providing a data type that is not compatible with the configured subfield’s type.
  • Exceeding the character limit (255) in a text field (single-line).
  • Trying to set a value for the separator (which is a technical field).
  • Providing a non-existent option as a value.
  • Providing a userKey of a non-existent user.
  • Providing a non-existent subfield name.
  • Providing a non-existent group index.
  • Providing an empty value for a required subfield.
  • Providing a value that is not compatible with the defined formatting, regular expression, or value mask.
  • Trying to exceed the configured number of groups for an issue.
  • Trying to create a new group without a required subfield.
  • Trying to perform an operation on a Bundled Field that hasn’t been configured (no configuration of such field has ever been saved).
  • Error during form validation while trying to update the issue (the possible reason may be a globally required field that hasn’t been filled).

Data types for date-specific custom fields

Before inserting a date-type sub-field value into a Date Picker/Date Time Picker custom field , you need to convert: java.util.Date -> java.sql.Timestamp

  • Value type custom field Date Picker and Date Time Picker is java.sql.Timestamp
  • Value type sub-field Date Picker and Date Time Picker is java.util.Date

Below is a script showing how you can set the value in custom fields.

In the script:

  • copying Date Picker sub-field value → Date Picker type custom field
  • copying sub-field Date Time Picker value → Date Time Picker type custom field
  • each stage of value retrieving and conversion has been reflected in logs to illustrate what happens in each step.
import org.apache.log4j.Level
import java.sql.Timestamp
import java.util.Date
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.component.ComponentAccessor
import com.intenso.jira.plugins.bundledfields.api.ExtensionBundledService
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

log.setLevel(Level.DEBUG)

@WithPlugin("com.intenso.jira.plugins.jsd-extender")

@PluginModule
ExtensionBundledService extensionBundledService

String ISSUE_OR_KEY = 'EXP-2'
String BUNDLED_FIELD_ID = "customfield_13300"
String DATE_PICKER_CUSTOM_FIELD_ID = "customfield_13301"
String DATE_TIME_PICKER_CUSTOM_FIELD_ID = "customfield_13302"

CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
IssueManager issueManager = ComponentAccessor.getIssueManager();
CustomField dateCustomField = customFieldManager.getCustomFieldObject(DATE_PICKER_CUSTOM_FIELD_ID);
CustomField dateTimeCustomField = customFieldManager.getCustomFieldObject(DATE_TIME_PICKER_CUSTOM_FIELD_ID);

Issue currentIssue = issueManager.getIssueObject(ISSUE_OR_KEY);
ApplicationUser currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();

def bundledField = extensionBundledService.getBundledField(ISSUE_OR_KEY, BUNDLED_FIELD_ID)
def dateSubfield = bundledField.getSubfield("Date Field 1", 0)
log.debug('Bundled Field DateField object: ' + dateSubfield)
log.debug('Bundled Field DateField value: ' + dateSubfield.getValue())
log.debug('Bundled Field DateField type: ' + dateSubfield.getValue().getClass())
log.debug('');

def dateTimeSubfield = bundledField.getSubfield("Date Time Field 1", 0)
log.debug('Bundled Field DateTimeField object: ' + dateTimeSubfield)
log.debug('Bundled Field DateTimeField value: ' + dateTimeSubfield.getValue())
log.debug('Bundled Field DateTimeField type: ' + dateTimeSubfield.getValue().getClass())
log.debug('');

Object customfieldDate = dateCustomField.getValue(currentIssue)
log.debug("Custom Field Date Picker value: " + customfieldDate);
log.debug("Custom Field Date Picker type: " + customfieldDate.getClass());
log.debug('');

Object customfieldDateTime = dateTimeCustomField.getValue(currentIssue)
log.debug("Custom Field Date Time Picker value: " + customfieldDateTime);
log.debug("Custom Field Date Time Picker type: " + customfieldDateTime.getClass());
log.debug('');

Timestamp convertedDate = toTimeStamp((Date)dateSubfield.getValue());
Timestamp convertedDateTime = toTimeStamp((Date)dateTimeSubfield.getValue());
log.debug("Bundled Field DateField converted to SQL Timestamp: " + convertedDate)
log.debug("Bundled Field DateTimeField converted to SQL Timestamp: " + convertedDateTime)

//update issue
currentIssue.setCustomFieldValue(dateCustomField, convertedDate);
currentIssue.setCustomFieldValue(dateTimeCustomField, convertedDateTime);
issueManager.updateIssue(currentUser, currentIssue, EventDispatchOption.DO_NOT_DISPATCH, false);

log.setLevel(Level.ERROR)

Timestamp toTimeStamp(Date date) {
    return new java.sql.Timestamp(date.getTime());
}

Need help?

If you can’t find the answer you need in our documentation, raise a support request. Include as much information as possible to help our support team resolve your issue faster.