How by jql to get issues in the form of JSON from JiraServer using java?

Oleksii Skachkov May 14, 2020

Hi all!

I am developing a plugin and I have the next problem:

- I retrieving from a user a JQL string like this: "project = DEMO"

- then I want to retrieve JSON with issues, but I can retrieve only List<Issue>

example:

String query = "project = DEMO";
Query conditionQuery = jqlQueryParser.parseQuery(query);
ApplicationUser searcher = jiraAuthenticationContext.getUser();
SearchResults results = searchService.search(searcher, conditionQuery, PagerFilter.getUnlimitedFilter());
List<Issue> issues = results.getIssues();

 

Object SearchResult is similar to JSON, retrieving from the link:

http://localhost:2990/jira/rest/api/2/search?jql=project+%3D+DEMO

This JSON is what I need. But I can’t understand how I can get it. Maybe somebody can give me advice - how to convert SearchResult to JSON, or maybe there is another way to get the JSON I need?

2 answers

1 vote
Jack Nolddor _Sweet Bananas_
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
May 20, 2020

A wild banana appears!

Hi @Oleksii Skachkov 

First note that the structure behind a server / data center is not the same that the one used in cloud, so probably the best approach is to work with Java classes provided on Server / Data Center apps, and develop a different application using rest services on cloud.

 

Saying that, if you need to use the issue JSON representation provided by Jira REST API itself, why don't simply make an http request to the endpoint and grab the data you need?

 

You can use the TrustedRequestFactory provided on SAL API (Shared Layer Access) to make http request using current user authorization token, in that way you don't need to know the user password at all.

Here is a quick example I did some time ago using groovy to call the Zephyr REST API within my Jira instance

 

/*
* @autor avillalobos
*
* To be use as a Script Listener for ProjectCreatedEvent
* Creates some test cycles by default when the project is created on behalf of a user who created the project
*
* Dependencies:
* - SAL-API >= 3.0
* - Zephyr add-on
* - ZAPI add-on
*/

package com.atsistemas.groovy

import com.atlassian.jira.project.Project
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.config.properties.APKeys
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.sal.api.net.Request.MethodType
import com.atlassian.sal.api.net.TrustedRequestFactory
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
import groovy.json.JsonOutput
import groovyx.net.http.URIBuilder
import groovyx.net.http.ContentType



// Zephyr test cycles creation
[
"Aceptacion",
"Sistema",
"Rendimiento",
"Seguridad"
].each{ cycleName ->
createCycle(cycleName, getProject().id)
}




/*
* Returns the base URL of this Jira instance
*/
String getBaseUrl()
{
return ComponentAccessor.applicationProperties.getString(APKeys.JIRA_BASEURL)
}


/*
* Returns the target project where test cycles will be created
* Formely, returns the project which generated this event
*/
Project getProject()
{
return event.project
}


/*
* Returns the user who will create the test cycles
* Formely, returns the user which generated this event
*/
ApplicationUser getAuthor()
{
return event.user
}


/*
* Returns the minimal payload needed to create a new Zehyr Test Cycle.
* See: https://getzephyr.docs.apiary.io/#reference/cycleresource/create-new-cycle/create-new-cycle
*/
String getCyclePayload(String cycleName, Long projectId)
{
return JsonOutput.toJson([
name: cycleName,
projectId: projectId,
versionId: "-1"
])
}


/*
* Create a Zephyr Test Cycle with the given name.
*/
void createCycle(String cicleName, Long projectId)
{
//Get the base URL of our instance
def baseUrl = getBaseUrl()
def host = new URIBuilder(baseUrl).host

//Create the request, including the method type and REST Endpoint we would like to call
def requestFactory = ScriptRunnerImpl.getOsgiService(TrustedRequestFactory)
def request = requestFactory.createTrustedRequest(MethodType.POST, "${baseUrl}/rest/zapi/latest/cycle")

//Add the username of the user we would like to authenticate with
request.addTrustedTokenAuthentication(host, getAuthor().username)

//Add the data to the request and specify the type of data being passed
request.setRequestBody(getCyclePayload(cicleName, projectId))
request.setHeader("Content-Type", ContentType.JSON.toString())

try {
def response = request.execute()
log.info "New Zephyr cycle created '${cicleName}'...."
log.debug response

} catch(e){
log.error "Failed to created '${cicleName}'...."
log.error e.message
}
}




Hope this help.
Regards

Ignacio Pulgar
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.
May 20, 2020

@Jack Nolddor _Sweet Bananas_Thanks for coming to my rescue! ;D

Jack Nolddor _Sweet Bananas_
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
May 20, 2020

You're welcome :)

Oleksii Skachkov May 20, 2020

Hi, @Jack Nolddor _Sweet Bananas_ 
Thanks for your help.

I am not familiar with groovy, but the general meaning is clear. Before trying to approach from my first question, I started from http reqest. And the general problem was how to get and use user authorization token. My working code:

 

private HttpResponse<JsonNode> getResponce(String url) throws UnirestException {
return Unirest.get(url)
.basicAuth("admin", "admin") //TODO change auth method
.header("Accept", "application/json")
.asJson();
}

 

I cannot use it that way, and I need to change the basic authorization to use an authorization token. No matter which library to use. Can you give an example?

I tried using TrustedRequestFactory from your example, but this factory is no longer available.

Also, I found that Jira Server cant generate REST API token, it can use only Basic and OAuth:   https://jira.atlassian.com/browse/JRASERVER-67869?_ga=2.241339585.254191367.1589777640-1416201942.1578820105


Can you direct me - on which side to look for a solution to Java?

Like Ignacio Pulgar likes this
Jack Nolddor _Sweet Bananas_
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
May 21, 2020

There is no way to use externals httpClients to call Jira itself if you want to avoid to hardcode user credentials. My code it a bit outdated since it worked on Jira 7, probably on Jira 8 you must use ApplicationLink#createAuthenticatedRequestFactory() or ApplicationLink#createImpersonatingAuthenticatedRequestFactory() methods.

Like Ignacio Pulgar likes this
Oleksii Skachkov May 22, 2020

Hi, @Jack Nolddor _Sweet Bananas_ 
Thanks for your help.

I tried to use AuthenticatedRequestFactory and AuthenticatedRequestFactory, but I did not succeed. And I decided to try on the other side. I founded how to convert JSON to SearchResult. I hope that there is a functionality that does the reverse work.

I didn't find it yet, but maybe you know about it?

Regards

Jack Nolddor _Sweet Bananas_
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
May 22, 2020

No idea to be honest, I've never used the json format I've always used Java beans such us MutableIssue, Project, ...

0 votes
Ignacio Pulgar
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.
May 19, 2020

Hi @Oleksii Skachkov ,

I'm not sure if this could be of any help:

https://stackoverflow.com/questions/14228912/how-to-convert-list-to-json-in-java

By the way, may you elaborate on why do you need to generate a JSON? I mean, is that the goal? Or is it just a way to access issue data in a way you are more comfortable with?

Regards

Oleksii Skachkov May 19, 2020

Hi, @Ignacio Pulgar.
Thanks for your help.

The solution you proposed does not work. The Issue consists of other objects that also refer to the Issue. Therefore, when converting to JSON, we get recursion and Stackoverflow.

Now I'm trying to solve the issue through a chain of objects: BeanBuilderFactory -> IssueBeanFactory -> IssueBean -> SearchResultsBean to make JSON from SearchResultsBean. But I am stuck on injection BeanBuilderFactory and IssueBeanFactory. Maybe you can help with it?

My plugin should work with the Server and with the Cloud. I want to write logic only once. It would be great to get the data for calculations in the same form both from the Server and from Cloud. In addition, it will be more convenient for me to process it with a JSON.

Regards

Like Ignacio Pulgar likes this
Ignacio Pulgar
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.
May 20, 2020

Interesting goal! This seems to be a question where @Jack Nolddor _Sweet Bananas_ (the best developer of Atlassian apps I know) may help! :)

Like Oleksii Skachkov likes this
Jack Nolddor _Sweet Bananas_
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
May 20, 2020

Hey! What an incredible summoning!

May I join the party? 🎉💙

Like Ignacio Pulgar likes this
Ignacio Pulgar
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.
May 20, 2020

Of course! You are always welcome! :)

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events