Apps documentation
Dynamic Forms for Jira
Dynamic Forms for Jira
6.x
5.x and older
FAQ
Release notes
Last updated Aug 24, 2021

Java API (ScriptRunner)

Learn how to use data from Bundled Fields in ScriptRunner

Dynamic Forms 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 key and the bundled field’s ID.

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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.

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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)

Remove group by parameter

Remove a group of the given parameter.

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

def group = bundledField.getGroup(0)

bundledField.removeGroup(group)

Remove group by index

Remove a group of the given index.

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

bundledField.removeGroup(2)

Remove first group

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

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

bundledField.removeFirstGroup()

Remove last group

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

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

bundledField.removeLastGroup()

Set subfield value in all groups

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

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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).

bundledField.setSubfieldValue(“Name”, “Jane Doe”, 2)

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.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

@WithPlugin("com.intenso.jira.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, bundledFieldId)

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

List of available signatures

BundledFieldService

BundledField getBundledField(String issueKey, String customFieldId)

BundledField

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()

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

Bundled Fields Java API - Validation Script
Bundled Fields Java API - Validation Script

Result

Bundled Fields Java API - Validation result
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:

Bundled Fields Java API - ScriptRunner postfunction's order
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.deviniti.plugins.bundledfields.api.issue.BundledFieldService
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.plugin.dynamic-forms")

@PluginModule
BundledFieldService bundledFieldService

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

def bundledField = bundledFieldService.getBundledField(issueKey, 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:
    Bundled Fields Java API - Getting the originId from the ScriptRunner console
    Bundled Fields Java API - Getting the originId from the ScriptRunner console
  • Database. You’ll find the originId in the AO_8CB340_DF_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):
    Bundled Fields Java API - Getting the originId from the Developer console in browser
    Bundled Fields Java API - Getting the originId from the Developer console in browser
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.