Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't generate properly formatted XML and JSON at the same time

Tags:

json

rest

xml

jaxb

First off, before you decide to close my question, I've tried this solution, but it's not working for me.

I have a REST service that is supposed to return JSON or XML depending on the Accept header. I can have it generate proper JSON, but not XML. When I fix the XML the JSON gets screwed. Below I'm presenting my code.

XML seems good, but JSON not

Message.java

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Message {
    int id;
    String text;

    @XmlElementWrapper
    @XmlElementRef
    List<Comment> comments;

    public Message() {

    }
    // getters and setters
}

Comment.java

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "comment")
public class Comment {
    int id;
    String text;

    public Comment() {

    }
    //getters and setters
}

MessageResource.java

import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;


@Path("messages")
public class MessageResource {

    DBUtils db = new DBUtils();

    @GET
    @Produces(MediaType.APPLICATION_XML)
    public Response getXML() {
        List<Message> messages = db.getMessages();
        return Response.ok(messages.toArray(new Message[messages.size()]), MediaType.APPLICATION_XML).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getJSON() {
        List<Message> messages = db.getMessages();
        return Response.ok(messages.toArray(new Message[messages.size()]), MediaType.APPLICATION_JSON).build();
    }
}

Here's the XML result, which is OK:

<messages>
    <message>
        <id>1</id>
        <text>Java is an OOP language.</text>
        <comments>
            <comment>
                <id>20</id>
                <text>That's correct.</text>
            </comment>
            <comment>
                <id>30</id>
                <text>test test</text>
            </comment>
        </comments>
    </message>
    <message>
        <id>1</id>
        <text>Java is an OOP language.</text>
        <comments>
            <comment>
                <id>20</id>
                <text>That's correct.</text>
            </comment>
            <comment>
                <id>30</id>
                <text>test test.</text>
            </comment>
        </comments>
    </message>
</messages>

And here's the JSON result, pay attention to the comments. All I need is a comments array.

[
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": {
      "comment": [
        {
          "id": 20,
          "text": "That's correct."
        },
        {
          "id": 30,
          "text": "test test"
        }
      ]
    }
  },
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": {
      "comment": [
        {
          "id": 20,
          "text": "That's correct."
        },
        {
          "id": 30,
          "text": "test test."
        }
      ]
    }
  }
]

Fixing the JSON messes up the XML response

If I remove the @XmlElementWrapper and @XmlElementRef annotations from the Message class, then it works for JSON, but not XML.

Message.jave

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Message {
    int id;
    String text;

    List<Comment> comments;

    public Message() {

    }
   //getters and setters
}

The Comment and MessageResource classes remain the same.

Here's the results I get:

JSON - OK

[
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": [
      {
        "id": 20,
        "text": "That's correct."
      },
      {
        "id": 30,
        "text": "test test"
      }
    ]
  },
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": [
      {
        "id": 20,
        "text": "That's correct."
      },
      {
        "id": 30,
        "text": "test test."
      }
    ]
  }
]

XML - WRONG

<messages>
    <message>
        <id>1</id>
        <text>Java is an OOP language.</text>
        <comments>
            <id>20</id>
            <text>That's correct.</text>
        </comments>
        <comments>
            <id>30</id>
            <text>test test</text>
        </comments>
    </message>
    <message>
        <id>1</id>
        <text>Java is an OOP language.</text>
        <comments>
            <id>20</id>
            <text>That's correct.</text>
        </comments>
        <comments>
            <id>30</id>
            <text>test test.</text>
        </comments>
    </message>
</messages>

Does anyone know how to make these two work together? The only solution I found to this is using JAXB for XML and GSON for JSON, but I have to manually create JSON objects using GSON.

Thanks!

like image 809
Turik Mirash Avatar asked May 02 '17 06:05

Turik Mirash


People also ask

Does the restful method support JSON or XML or both format?

The same resource may return either XML or JSON depending upon the request, but it shouldn't return both at the same time.

Are JSON and XML equivalent?

JSON is simpler than XML, but XML is more powerful. For common applications, JSON's terse semantics result in code that is easier to follow. For applications with complex requirements surrounding data interchange, such as in enterprise, the powerful features of XML can significantly reduce software risk.

Why must one use JSON over XML?

There are 3 commonly discussed benefits of JSON over XML: In most scenarios, JSON is undoubtedly easier to read in its expanded form than XML. JSON can have a substantially lower character count reducing the overhead in data transfers. JSON is much easier to parse.

Which is more secure JSON or XML?

Key Difference Between JSON and XML JSON is less secured whereas XML is more secure compared to JSON. JSON supports only UTF-8 encoding whereas XML supports various encoding formats.


1 Answers

My proposed solution uses JAXB for XML (like you). But for JSON it uses Jackson-JAXRS (unlike you), as for example described in this answer. So, instead of using GSON you would need to use Jackson-JAXRS (for example from Maven).

To get the desired XML and JSON output, you need to tune the annotations of the List<Comment> comments property in your Message class.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Message {
    int id;
    String text;

    @XmlElementWrapper(name="comments")
    @XmlElementRef
    @JsonUnwrapped
    List<Comment> comments;

    //getters and setters
}

By @XmlElementRef you get each Comment object written as a <comment> element. Finally, by @XmlElementWrapper(name="comments") you get all these wrapped in a <comments> element.

The XML output is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<messages>
  <message>
    <id>1</id>
    <text>Java is an OOP language.</text>
    <comments>
      <comment>
        <id>20</id>
        <text>That's correct.</text>
      </comment>
      <comment>
        <id>30</id>
        <text>test test.</text>
      </comment>
    </comments>
  </message>
  <message>
    <id>1</id>
    <text>Java is an OOP language.</text>
    <comments>
      <comment>
        <id>20</id>
        <text>That's correct.</text>
      </comment>
      <comment>
        <id>30</id>
        <text>test test.</text>
      </comment>
    </comments>
  </message>
</messages>

By @JsonUnwrapped (imported from package com.fasterxml.jackson.annotation) you get the List<Comment> comments written as a plain array of objects.

The JSON output is:

[
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": [
      {
        "id": 20,
        "text": "That's correct."
      },
      {
        "id": 30,
        "text": "test test."
      }
    ]
  },
  {
    "id": 1,
    "text": "Java is an OOP language.",
    "comments": [
      {
        "id": 20,
        "text": "That's correct."
      },
      {
        "id": 30,
        "text": "test test."
      }
    ]
  }
]
like image 120
Thomas Fritsch Avatar answered Sep 27 '22 22:09

Thomas Fritsch