Cannot deserialize IssueField coming from webhook event

D. U. January 22, 2018

 

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

0 votes
Domenico Manzo _Actonic_
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.
January 23, 2018

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);  
D. U. January 23, 2018

Okay...I'll try but how can I combine that with Jackson?

D. U. January 23, 2018

...and where is ResourceUtil from?

D. U. January 23, 2018

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?

D. U. January 23, 2018

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

D. U. January 23, 2018

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.

D. U. January 24, 2018

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