Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root


1 badge earned


Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!


Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.


Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!


Custom Sprint Report: getting sprint info from Java API (JIRA Software v7+ server)



I wanted to share some of my trials and tribulations while working on a custom sprint report for Jira Software (v7.3) server using the Plugins2 framework, in case there were others trying to do the same.


I started this project before knowing that the agile features of JIRA Software are not exposed in the Java API. After some digging found suggestions to use the REST API, which did have access to agile entities. This involved building a little HTTP client in my code from scratch (since Jira Java REST API Client is not supported past JIRA v6 because of course it isn't).

Important part

While I was testing my client however, I found that in fact, you can get a good amount of information about sprints from the Java API using the getValue() method of the CustomField class. That is, you can get access to an instance of CustomField object that represents an issue's sprints from the CustomFieldManager class (provided by the ComponentAccessor class, for example), and then call the getValue() method, which returns a list of info about the sprint. You can then parse the list for the needed info (using regex patterns, for example).

An example of the output of getValue() is shown below. This issue was in two sprints, Sprint 1 and Sprint 2. Sprint 1 is closed and started on 2017-05-31, while Sprint 2 is a Future sprint with no start date, etc.

[com.atlassian.greenhopper.service.sprint.Sprint@77e7bf34[id=225,rapidViewId=161,state=CLOSED,name=Sprint 1,startDate=2017-05-31T10:31:07.779-05:00,endDate=2017-06-07T10:31:00.000-05:00,completeDate=2017-12-11T14:12:16.082-06:00,sequence=225], com.atlassian.greenhopper.service.sprint.Sprint@68792939[id=400,rapidViewId=161,state=FUTURE,name=Sprint 2,startDate=,endDate=,completeDate=,sequence=400]]


If the report you're making requires any of this info, you don't need to access the REST API, and can get it from the Java API.

  • Sprint name
  • Agile board ID
  • Sprint state
  • Sprint start date
  • Sprint end date
  • Sprint completed date

I hope this info is helpful for anyone in my position who just wants to make some basic custom sprint reports!



Thanks for posting! This got me started on the right track. I ended up also going down the rabbit hole of casting the getValue() Object to an  ArrayList<Sprint> instead of parsing the toString() output.

Could you please paste the part of your code with the CustomFields here?


I am getting a similar output by using:

 IssueField field = issue.getFieldByName("Sprint");



The problem is, I do not know how I could extract the attributes from the following output:


[com.atlassian.greenhopper.service.sprint.Sprint@77e7bf34[id=225,rapidViewId=161,state=CLOSED,name=Sprint 1,startDate=2017-05-31T10:31:07.779-05:00,endDate=2017-06-07T10:31:00.000-05:00,completeDate=2017-12-11T14:12:16.082-06:00,sequence=225], com.atlassian.greenhopper.service.sprint.Sprint@68792939[id=400,rapidViewId=161,state=FUTURE,name=Sprint 2,startDate=,endDate=,completeDate=,sequence=400]]


Any suggestion?

The easy way is just to parse the string returned from getValue().toString() - what you pasted.

Alternatively, after a little extra work you can cast the object returned by getValue() to what it actually is: an ArrayList<Sprint>. This requires adding a dependency on the library that contains the definition of the Sprint class: com.atlassian.greenhopper.service.sprint.*. This page goes into detail on that topic

Like georgiossalon likes this

Many thanks for replying.


1 Method)

By parsing you mean, writing my self a method that tries to get the attributes somehow from the String? 


2 Method)

I have tried the following:

ArrayList<Sprint> sprints = field.getValue();

but I am getting the following error:

Incompatible types.
Required: java.util.ArrayList<com.atlassian.greenhopper.service.sprint.Sprint>
Found: java.lang.Object



ArrayList<Sprint> sprints = (ArrayList<Sprint>) field.getValue();

Exception in thread "main" java.lang.ClassCastException:

class org.codehaus.jettison.json.JSONArray cannot be cast to class java.util.ArrayList (org.codehaus.jettison.json.JSONArray is in unnamed module of loader 'app'; java.util.ArrayList is in module java.base of loader 'bootstrap')



 I am getting ---> org.codehaus.jettison.json.JSONArray

After trying though

JSONArray jsonArray = new JSONArray(field.getValue());

I am getting --> Cannot resolve constructor 'JSONArray(java.lang.Object)' 

I am kind of lost right now.

1 Method )

Yes. Using a regex string as suggested in the original post.

2 Method)

I will just paste my example code. This may not be drop-in-ready in your environment, but should provide you enough context to get you over the hump. Note you will need to `import com.atlassian.greenhopper.service.sprint.*;` which requires following the directions in the original link I posted.

public void validate(Map transientVars, Map args, PropertySet ps) throws InvalidInputException {
Issue issue = (Issue) transientVars.get("issue");
log.debug("Processing issue '" + issue.getKey() + "'");

List<CustomField> customFields = customFieldManager.getCustomFieldObjects(issue);
log.debug("Number of fields in issue '" + customFields.size() + "'");

for (CustomField field : customFields) {
log.debug("Checking field name '" + field.getFieldName() + "'");

if (field.getFieldName().equals("Sprint")) {
log.debug("Found 'Sprint' field");

Object fieldValue = field.getValue(issue);

if (fieldValue == null) {
log.debug("Sprint value is null");
// TODO: throw exception
} else {
// Get list of sprints this issue has been assigned to
ArrayList<Sprint> sprintList = (ArrayList<Sprint>) fieldValue;

log.debug("The issue has been assigned to the following sprints: ");
for(Sprint sprint : sprintList) {
log.debug("Name = '" + sprint.getName() + "' State = '" + sprint.getState() + "'");

// Are any of them active?
boolean anyActiveSprints = Iterables.any(sprintList,
new Predicate<Sprint>() {
public boolean apply(Sprint sprint) {
return sprint.isActive();

if (!anyActiveSprints) {
log.debug("None of the assigned sprints are active.");
// TODO: throw exception

 Sorry for the poor style there - this site is removing all my indentation spaces .

Like georgiossalon likes this

Thank you again for replying.


How do you even get the Class:



When I import with Gradle the following lib

compile group: 'com.atlassian.jira', name: 'jira-api', version: '7.6.1'

from repository

maven { url''}

I get constantly the following error:

jta:jta:1.0.1 FAILED ->Build: ...\Could not find jta:jta:1.0.1. 

I have tried to download only the jta lib and install it, but it still doesnt work.

I also have tried the newer version: 

compile group: 'com.atlassian.jira', name: 'jira-api', version: '7.11.2'

but I still get the same error.

To that I can only write a part of your code without gettint an error like this:

List<CustomField> customFields = ComponentAccessor.getCustomFieldManager().getCustomFieldObjects((com.atlassian.jira.issue.Issue) issue);

so by additionally using the "ComponentAccessor".


I do not understand why "JIRA" made the extraction of Data so difficult. It just doesnt make any sense to me.

Tim Eddelbüttel
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.
Jun 23, 2020

I've also struggeld with fetching Sprint informations like issues not completed in current sprint. After a bit ob searching trouch the APIs I've found that the HistoricSprintDataFactory helps to fetch the Sprint information.

After googling for the Class I've spotted that there is a ScriptRunner example :D


Log in or Sign up to comment