Cannot deserialize IssueField coming from webhook event Edited

 

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?

1 answer

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'll try but how can I combine that with Jackson?

...and where is ResourceUtil from?

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?

...internally Atlassian is using org.codehaus.jettison.json.JSONObject !!!

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.

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

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Nov 27, 2018 in Portfolio for Jira

Introducing a new planning experience in Portfolio for Jira (Server/DC)

In the past, Portfolio for Jira required a high degree of detail–foresight that was unrealistic for many businesses to   have–in   order to produce a reliable long-term roadmap. We're tur...

2,946 views 19 22
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you