简体   繁体   English

如何在使用 Jersey 使用 ZEEBB106BBF13742E3BE15A1 将 json 解组为 java bean 时使用一些间接性

[英]how to use some indirection when unmarshalling json to java bean using Jersey using jaxb annotations

I'm trying to unmarshall some received json (from Jira restful web service).我正在尝试解组一些收到的 json (来自 Jira restful web 服务)。

Problem is: an "issue" has a "summary" property and a list of fields.问题是:“问题”具有“摘要”属性和字段列表。

Summary is not present as an attribute in the received json, but as a value of the "fields" attribute.摘要不是作为属性出现在收到的 json 中,而是作为“字段”属性的值。 I insist on unmarshalling to this structure:我坚持解组到这个结构:

@XmlRootElement
class Issue {
   String summary;
   List<Field> fields;
   // getters/setters and lots of other fields
}

Received JSON:收到 JSON:

{
    "expand":"html",
    "self":"https://example.com/jira/rest/api/latest/issue/XYZ-1234",
    "key":"XYZ-1234",
    "fields":
    {
        "summary":
        {
            "name":"summary",
            "type":"java.lang.String",
            "value":"test 1234"
        },
        "customfield_10080":
        {
            "name":"Testeur",
            "type":"com.atlassian.jira.plugin.system.customfieldtypes:userpicker"
        },
        "status":
        {
            "name":"status",
            "type":"com.atlassian.jira.issue.status.Status",
            "value":
            {
                "self":"https://example.com/jira/rest/api/latest/status/5",
                "name":"Resolved"
            }
        },
        ...            
    },
    "transitions":"https://example.com/jira/rest/api/latest/issue/XYZ-1234/transitions"
}

I don't want to use Jira's own client (too many dependencies which I don't want in my app).我不想使用 Jira 自己的客户端(我不想在我的应用程序中使用太多依赖项)。

edit: I asked my question another way to try to make it clear: how to map a bean structure to a different schema with jax-rs编辑:我用另一种方式问了我的问题以试图弄清楚: how to map a bean structure to a different schema with jax-rs

Your annotated class should be bijective: it should allow to generate the same input from which it was unmarshalled.您带注释的 class应该是双射的:它应该允许生成与解组时相同的输入。 If you still want to use a non-bijective object graph, you can use @XmlAnyElement the following way:如果您仍想使用非双射 object 图,可以通过以下方式使用@XmlAnyElement

public class Issue {

    @XmlElement(required = true)
    protected Fields fields;

    public Fields getFields() {
        return fields;
    }
}

In the input you gave, fields is not a list, but a field (JSON uses [] to delimit lists):在您提供的输入中,字段不是列表,而是字段(JSON 使用 [] 分隔列表):

public class Fields {

    @XmlElement(required = true)
    protected Summary summary;

    @XmlAnyElement
    private List<Element> fields;

    public List<Element> getFields() {
        return fields;
    }

    public Summary getSummary() {
        return summary;
    }
}

In order to catch Summary, you'll have to define a dedicated class.为了捕捉摘要,您必须定义一个专用的 class。 Remaining fields will be grouped in the fields list of elements.剩余的字段将被分组在元素的fields列表中。

public class Summary {

    @XmlAttribute
    protected String name;

    public String getName() {
        return name;
    }
}

Below, a unit test using your input shows that everything work:下面,使用您的输入进行的单元测试表明一切正常:

public class JaxbTest {
    @Test
    public void unmarshal() throws JAXBException, IOException {
        URL xmlUrl = Resources.getResource("json.txt");
        InputStream stream = Resources.newInputStreamSupplier(xmlUrl).getInput();
        Issue issue = parse(stream, Issue.class);

        assertEquals("summary", issue.getFields().getSummary().getName());

        Element element = issue.getFields().getFields().get(0);
        assertEquals("customfield_10080", element.getTagName());
        assertEquals("name", element.getFirstChild().getLocalName());
        assertEquals("Testeur", element.getFirstChild().getFirstChild().getTextContent());
    }

    private <T> T parse(InputStream stream, Class<T> clazz) throws JAXBException {
        JSONUnmarshaller unmarshaller = JsonContextNatural().createJSONUnmarshaller();
        return unmarshaller.unmarshalFromJSON(stream, clazz);
    }

    private JSONJAXBContext JsonContextNatural() throws JAXBException {
        return new JSONJAXBContext(JSONConfiguration.natural().build(), Issue.class);
    }
}

This tests shows that without using dedicated classes, your code will quickly be hard to read.该测试表明,如果不使用专用类,您的代码将很快变得难以阅读。

You will need those maven dependencies to run it:您将需要这些 maven 依赖项来运行它:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>r08</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.6</version>
</dependency>
{
    "expand":"html",
        "self":"xxx/jira/rest/api/latest/issue/EPC-2731";,
        "key":"EPC-2731",
        "fields":{
            "summary":{
                "name":"summary",
                "type":"java.lang.String",
                "value":"Fwd: commentaires vides dans FicheSousGroupement" 
            },
            "timetracking":{
                "name":"timetracking",
                "type":"com.atlassian.jira.issue.fields.TimeTrackingSystemField",
                "value":{
                    "timeestimate":0,
                    "timespent":60 
                } 
            },
            "issuetype":{
                "name":"issuetype",
                "type":"com.atlassian.jira.issue.issuetype.IssueType",
                "value":{
                    "self":"xxx/jira/rest/api/latest/issueType/2";,
                    "name":"Nouvelle fonctionnalité",
                    "subtask":false 
                } 
            },
            "customfield_10080":{
                "name":"Testeur",
                "type":"com.atlassian.jira.plugin.system.customfieldtypes:userpicker" 
            },

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM