I created a JIRA bug and sent the subsequent generated event to a SpringBoot a via webhook. That works so far. In the SpringBoot app I tried to deserialize the received JSON. To achieve this I have an IssueEvent class which has an Issue field:
package my.package.domain.jira.entity;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.User;
/**
* RootObject JSON
*
*/
public class IssueEvent implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4467263405878138432L;
private Long timestamp;
private String webhookEvent;
@JsonProperty("issue_event_type_name")
private String issueEventTypeName;
private User user;
private Issue issue;
// private Changelog changelog;
private ChangelogGroup changelog;
... }
Here's the JSON generated by JIRA when creating a bug/issue:
{
"timestamp": 1516646881687,
"webhookEvent": "jira:issue_created",
"issue_event_type_name": "issue_created",
"user": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "abla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"issue": {
"id": "10610",
"self": "http://localhost:9090/rest/api/2/issue/10610",
"key": "COVA-77",
"fields": {
"issuetype": {
"self": "http://localhost:9090/rest/api/2/issuetype/10004",
"id": "10004",
"description": "Ein Problem, das die Funktionen des Produkts beeinträchtigt oder verhindert.",
"iconUrl": "http://localhost:9090/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",
"name": "Bug",
"subtask": false,
"avatarId": 10303
},
"components": [],
"timespent": null,
"timeoriginalestimate": null,
"description": "Teeest",
"project": {
"self": "http://localhost:9090/rest/api/2/project/10000",
"id": "10000",
"key": "COVA",
"name": "CoVA",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/projectavatar?avatarId=10324",
"24x24": "http://localhost:9090/secure/projectavatar?size=small&avatarId=10324",
"16x16": "http://localhost:9090/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "http://localhost:9090/secure/projectavatar?size=medium&avatarId=10324"
}
},
"fixVersions": [
{
"self": "http://localhost:9090/rest/api/2/version/10000",
"id": "10000",
"name": "Version 1.0",
"archived": false,
"released": true,
"releaseDate": "2017-11-29"
}
],
"aggregatetimespent": null,
"resolution": null,
"timetracking": {},
"customfield_10005": "0|i000dj:",
"attachment": [],
"aggregatetimeestimate": null,
"resolutiondate": null,
"workratio": -1,
"summary": "Bug-Tester",
"lastViewed": null,
"watches": {
"self": "http://localhost:9090/rest/api/2/issue/COVA-77/watchers",
"watchCount": 0,
"isWatching": false
},
"creator": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "abla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"subtasks": [],
"created": "2018-01-22T19:48:01.494+0100",
"reporter": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "blabla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"customfield_10000": null,
"aggregateprogress": {
"progress": 0,
"total": 0
},
"priority": {
"self": "http://localhost:9090/rest/api/2/priority/3",
"iconUrl": "http://localhost:9090/images/icons/priorities/medium.svg",
"name": "Medium",
"id": "3"
},
"labels": [
"Bug",
"Test"
],
"customfield_10004": [
"com.atlassian.greenhopper.service.sprint.Sprint@327e23ff[id=1,rapidViewId=1,state=ACTIVE,name=Sample Sprint 2,startDate=2017-11-30T02:29:06.805+01:00,endDate=2017-12-14T02:49:06.805+01:00,completeDate=<null>,sequence=1,goal=<null>]"
],
"environment": "Buuuug",
"timeestimate": null,
"aggregatetimeoriginalestimate": null,
"versions": [
{
"self": "http://localhost:9090/rest/api/2/version/10000",
"id": "10000",
"name": "Version 1.0",
"archived": false,
"released": true,
"releaseDate": "2017-11-29"
}
],
"duedate": null,
"progress": {
"progress": 0,
"total": 0
},
"comment": {
"comments": [],
"maxResults": 0,
"total": 0,
"startAt": 0
},
"issuelinks": [
{
"id": "10410",
"self": "http://localhost:9090/rest/api/2/issueLink/10410",
"type": {
"id": "10000",
"name": "Blocks",
"inward": "is blocked by",
"outward": "blocks",
"self": "http://localhost:9090/rest/api/2/issueLinkType/10000"
},
"outwardIssue": {
"id": "10609",
"key": "COVA-76",
"self": "http://localhost:9090/rest/api/2/issue/10609",
"fields": {
"summary": "254z245z245z2",
"status": {
"self": "http://localhost:9090/rest/api/2/status/10000",
"description": "",
"iconUrl": "http://localhost:9090/",
"name": "Aufgaben",
"id": "10000",
"statusCategory": {
"self": "http://localhost:9090/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "Aufgaben"
}
},
"priority": {
"self": "http://localhost:9090/rest/api/2/priority/3",
"iconUrl": "http://localhost:9090/images/icons/priorities/medium.svg",
"name": "Medium",
"id": "3"
},
"issuetype": {
"self": "http://localhost:9090/rest/api/2/issuetype/10004",
"id": "10004",
"description": "Ein Problem, das die Funktionen des Produkts beeinträchtigt oder verhindert.",
"iconUrl": "http://localhost:9090/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",
"name": "Bug",
"subtask": false,
"avatarId": 10303
}
}
}
}
],
"votes": {
"self": "http://localhost:9090/rest/api/2/issue/COVA-77/votes",
"votes": 0,
"hasVoted": false
},
"worklog": {
"startAt": 0,
"maxResults": 20,
"total": 0,
"worklogs": []
},
"assignee": null,
"updated": "2018-01-22T19:48:01.494+0100",
"status": {
"self": "http://localhost:9090/rest/api/2/status/10000",
"description": "",
"iconUrl": "http://localhost:9090/",
"name": "Aufgaben",
"id": "10000",
"statusCategory": {
"self": "http://localhost:9090/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "Aufgaben"
}
}
}
},
"changelog": {
"id": "10720",
"items": [
{
"field": "Link",
"fieldtype": "jira",
"from": null,
"fromString": null,
"to": "COVA-76",
"toString": "This issue blocks COVA-76"
}
]
}
}
Since the JIRA classes don't have a prameterless default constructors I tried to use Mixins. It works well for the User but seems not for Issue class:
package my.package.domain.jira.util;
import java.net.URI;
import java.util.Collection;
import java.util.Set;
import org.joda.time.DateTime;
import com.atlassian.jira.rest.client.api.domain.Attachment;
import com.atlassian.jira.rest.client.api.domain.BasicComponent;
import com.atlassian.jira.rest.client.api.domain.BasicPriority;
import com.atlassian.jira.rest.client.api.domain.BasicProject;
import com.atlassian.jira.rest.client.api.domain.BasicVotes;
import com.atlassian.jira.rest.client.api.domain.BasicWatchers;
import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
import com.atlassian.jira.rest.client.api.domain.Comment;
import com.atlassian.jira.rest.client.api.domain.IssueField;
import com.atlassian.jira.rest.client.api.domain.IssueLink;
import com.atlassian.jira.rest.client.api.domain.IssueType;
import com.atlassian.jira.rest.client.api.domain.Operations;
import com.atlassian.jira.rest.client.api.domain.Resolution;
import com.atlassian.jira.rest.client.api.domain.Status;
import com.atlassian.jira.rest.client.api.domain.Subtask;
import com.atlassian.jira.rest.client.api.domain.TimeTracking;
import com.atlassian.jira.rest.client.api.domain.User;
import com.atlassian.jira.rest.client.api.domain.Version;
import com.atlassian.jira.rest.client.api.domain.Worklog;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
*/
public abstract class IssueMixin {
@JsonCreator
public IssueMixin(@JsonProperty("summary") String summary, @JsonProperty("self") URI self, @JsonProperty("key") String key,
@JsonProperty("id") Long id, @JsonProperty("project") BasicProject project, @JsonProperty("issueType") IssueType issueType,
@JsonProperty("status") Status status, @JsonProperty("description") String description, @JsonProperty("priority") BasicPriority priority,
@JsonProperty("resolution") Resolution resolution, @JsonProperty("attachments") Collection<Attachment> attachments, @JsonProperty("reporter") User reporter,
@JsonProperty("assignee") User assignee, @JsonProperty("creationDate") DateTime creationDate, @JsonProperty("updateDate") DateTime updateDate,
@JsonProperty("dueDate") DateTime dueDate, @JsonProperty("affectedVersion") Collection<Version> affectedVersion,
@JsonProperty("fixVersions") Collection<Version> fixVersions, @JsonProperty("components") Collection<BasicComponent> components,
@JsonProperty("timeTracking") TimeTracking timeTracking, @JsonProperty("fields") Collection<IssueField> issueFields,
@JsonProperty("comments") Collection<Comment> comments, @JsonProperty("transitionsUri") URI transitionsUri,
@JsonProperty("issueLinks") Collection<IssueLink> issueLinks, @JsonProperty("votes") BasicVotes votes, @JsonProperty("worklogs") Collection<Worklog> worklogs,
@JsonProperty("watchers") BasicWatchers watchers, @JsonProperty("expandos") Iterable<String> expandos, @JsonProperty("subtasks") Collection<Subtask> subtasks,
@JsonProperty("changelog") Collection<ChangelogGroup> changelog, @JsonProperty("operations") Operations operations, @JsonProperty("labels") Set labels ) {}
}
This Mixin matches exactly the constructor of class Issue from package com.atlassian.jira.rest.client.api.domain.
I get the following Exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
at [Source: {
"timestamp": 1516692474575,
"webhookEvent": "jira:issue_created",
"issue_event_type_name": "issue_created",
"user": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "abla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"issue": {
"id": "10623",
"self": "http://localhost:9090/rest/api/2/issue/10623",
"key": "COVA-90",
"fields": {
"issuetype": {
"self": "http://localhost:9090/rest/api/2/issuetype/10004",
"id": "10004",
"description": "Ein Problem, das die Funktionen des Produkts beeinträchtigt oder verhindert.",
"iconUrl": "http://localhost:9090/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",
"name": "Bug",
"subtask": false,
"avatarId": 10303
},
"components": [],
"timespent": null,
"timeoriginalestimate": null,
"description": "dhmedhmed",
"project": {
"self": "http://localhost:9090/rest/api/2/project/10000",
"id": "10000",
"key": "COVA",
"name": "CoVA",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/projectavatar?avatarId=10324",
"24x24": "http://localhost:9090/secure/projectavatar?size=small&avatarId=10324",
"16x16": "http://localhost:9090/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "http://localhost:9090/secure/projectavatar?size=medium&avatarId=10324"
}
},
"fixVersions": [
{
"self": "http://localhost:9090/rest/api/2/version/10000",
"id": "10000",
"name": "Version 1.0",
"archived": false,
"released": true,
"releaseDate": "2017-11-29"
}
],
"aggregatetimespent": null,
"resolution": null,
"timetracking": {},
"customfield_10005": "0|i000gf:",
"attachment": [],
"aggregatetimeestimate": null,
"resolutiondate": null,
"workratio": -1,
"summary": "jrzj",
"lastViewed": null,
"watches": {
"self": "http://localhost:9090/rest/api/2/issue/COVA-90/watchers",
"watchCount": 0,
"isWatching": false
},
"creator": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "abla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"subtasks": [],
"created": "2018-01-23T08:27:54.388+0100",
"reporter": {
"self": "http://localhost:9090/rest/api/2/user?username=bla",
"name": "bla",
"key": "abla",
"emailAddress": "a.b@xyz.com",
"avatarUrls": {
"48x48": "http://localhost:9090/secure/useravatar?avatarId=10336",
"24x24": "http://localhost:9090/secure/useravatar?size=small&avatarId=10336",
"16x16": "http://localhost:9090/secure/useravatar?size=xsmall&avatarId=10336",
"32x32": "http://localhost:9090/secure/useravatar?size=medium&avatarId=10336"
},
"displayName": "bla",
"active": true,
"timeZone": "Europe/Berlin"
},
"customfield_10000": null,
"aggregateprogress": {
"progress": 0,
"total": 0
},
"priority": {
"self": "http://localhost:9090/rest/api/2/priority/3",
"iconUrl": "http://localhost:9090/images/icons/priorities/medium.svg",
"name": "Medium",
"id": "3"
},
"labels": [
"Test",
"Bug"
],
"customfield_10004": [
"com.atlassian.greenhopper.service.sprint.Sprint@14d495fe[id=1,rapidViewId=1,state=ACTIVE,name=Sample Sprint 2,startDate=2017-11-30T02:29:06.805+01:00,endDate=2017-12-14T02:49:06.805+01:00,completeDate=<null>,sequence=1,goal=<null>]"
],
"environment": "dghndghmnedghmn",
"timeestimate": null,
"aggregatetimeoriginalestimate": null,
"versions": [
{
"self": "http://localhost:9090/rest/api/2/version/10000",
"id": "10000",
"name": "Version 1.0",
"archived": false,
"released": true,
"releaseDate": "2017-11-29"
}
],
"duedate": null,
"progress": {
"progress": 0,
"total": 0
},
"comment": {
"comments": [],
"maxResults": 0,
"total": 0,
"startAt": 0
},
"issuelinks": [
{
"id": "10421",
"self": "http://localhost:9090/rest/api/2/issueLink/10421",
"type": {
"id": "10000",
"name": "Blocks",
"inward": "is blocked by",
"outward": "blocks",
"self": "http://localhost:9090/rest/api/2/issueLinkType/10000"
},
"outwardIssue": {
"id": "10616",
"key": "COVA-83",
"self": "http://localhost:9090/rest/api/2/issue/10616",
"fields": {
"summary": "fj,t.uoöpuz.ötultl",
"status": {
"self": "http://localhost:9090/rest/api/2/status/10000",
"description": "",
"iconUrl": "http://localhost:9090/",
"name": "Aufgaben",
"id": "10000",
"statusCategory": {
"self": "http://localhost:9090/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "Aufgaben"
}
},
"priority": {
"self": "http://localhost:9090/rest/api/2/priority/3",
"iconUrl": "http://localhost:9090/images/icons/priorities/medium.svg",
"name": "Medium",
"id": "3"
},
"issuetype": {
"self": "http://localhost:9090/rest/api/2/issuetype/10004",
"id": "10004",
"description": "Ein Problem, das die Funktionen des Produkts beeinträchtigt oder verhindert.",
"iconUrl": "http://localhost:9090/secure/viewavatar?size=xsmall&avatarId=10303&avatarType=issuetype",
"name": "Bug",
"subtask": false,
"avatarId": 10303
}
}
}
}
],
"votes": {
"self": "http://localhost:9090/rest/api/2/issue/COVA-90/votes",
"votes": 0,
"hasVoted": false
},
"worklog": {
"startAt": 0,
"maxResults": 20,
"total": 0,
"worklogs": []
},
"assignee": null,
"updated": "2018-01-23T08:27:54.388+0100",
"status": {
"self": "http://localhost:9090/rest/api/2/status/10000",
"description": "",
"iconUrl": "http://localhost:9090/",
"name": "Aufgaben",
"id": "10000",
"statusCategory": {
"self": "http://localhost:9090/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "Aufgaben"
}
}
}
},
"changelog": {
"id": "10742",
"items": [
{
"field": "Link",
"fieldtype": "jira",
"from": null,
"fromString": null,
"to": "COVA-83",
"toString": "This issue blocks COVA-83"
}
]
}
}; line: 1, column: 709] (through reference chain: de.vwncova.defectadapter.domain.jira.entity.IssueEvent["issue"]->com.atlassian.jira.rest.client.api.domain.Issue["fields"])
It seems as if the JSON generated from JIRA does not its own class Issue.
How can I solve this problem?
Try to use com.atlassian.jira.rest.client.internal.json.IssueJsonParser from atlassian-jira-rest-java-client
Something like:
private Issue parseIssue(final String resourcePath) throws JSONException {
final JSONObject issueJson = ResourceUtil.getJsonObjectFromResource(resourcePath);
final IssueJsonParser parser = new IssueJsonParser();
return parser.parse(issueJson);
}
Okay...I see that I don't need ResourceUtil.getJsonObjectFromResource because I do already have it because the JSON comes as parameter...
Is the JSONObject still available in Atlassian JIRA 7.1.6?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am using JIRA 7.1.6.
I found out that the IssueEvent class is in jira-api but when I use this dependency in my POM the build fails with an exception that dependency jta 1.0.1 cannot be found...and it doesn't work when I put the jta dependency in my POM a well.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Okay...I had to exclude the JTA portion from the jira-api dependency.
However, I still can't get the JSON deserialized to the JIRA domain objects...
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.