不能将杰克逊来自webhook事件的JIRA IssueField反序列化

时间:2018-01-23 07:52:35

标签: json jackson jira json-deserialization

我创建了一个JIRA错误,并通过webhook将后续生成的事件发送到SpringBoot a。这到目前为止工作。在SpringBoot应用程序中,我尝试反序列化收到的JSON。为了实现这一点,我有一个IssueEvent类,它有一个Issue字段:

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 ChangelogGroup changelog;
...
}

这是JIRA在创建错误/问题时生成的JSON:

{
"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"
        }
    ]
}

}

由于JIRA类没有无参数的默认构造函数,因此我尝试使用 Mixins 。它适用于User类,但似乎不适用于Issue类:

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 ) {}
}

这个Mixin与包com.atlassian.jira.rest.client.api.domain中的类Issue的构造函数完全匹配。

我得到以下例外:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: 
 {...JSON from above...}; line: 1, column: 709] (through reference chain: my.package.domain.jira.entity.IssueEvent["issue"]->com.atlassian.jira.rest.client.api.domain.Issue["fields"])

似乎从JIRA生成的JSON与其自己的类Issue不匹配。

Issue类周围的JSON包含更多代码(可能是com.atlassian.jira.event.issue.IssueEvent类)。首先我尝试自己编写这个POJO,但我更喜欢使用JIRA域类......但是如何引用这个类。 Trynig使用jira-api依赖失败,缺少jta 1.0.1依赖。

我该如何解决这个问题?

好。我发现我必须排除jira-api依赖项内部使用的JTA依赖项:

<dependency>
    <groupId>com.atlassian.jira</groupId>
    <artifactId>jira-api</artifactId>
    <version>${jira.version}</version>
    <scope>provided</scope>
    <exclusions>
        <exclusion>
            <groupId>jta</groupId>
            <artifactId>jta</artifactId>
        </exclusion>
    </exclusions>
</dependency>

我还不知道如何将JSON解码/反序列化为JIRA域对象......

0 个答案:

没有答案