8

I am using Jersey to make some of my services RESTful.

My REST service call returns me

{"param1":"value1", "param2":"value2",...."paramN":"valueN"}

But, I want it to return

["param1":"value1", "param2":"value2",...."paramN":"valueN"]

What are the changes I need to make in the code below?

@GET
@Produces(MediaType.APPLICATION_JSON)
public List<com.abc.def.rest.model.SimplePojo> getSomeList() {
    /* 
            Do something
    */
    return listOfPojos;
}

Part of my web.xml file looks like this

    <servlet>
        <servlet-name>Abc Jersey REST Service</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>com.abc.def.rest</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>

Thanks!

Ayaz Pasha
  • 1,045
  • 6
  • 13
  • 28
  • What you want to return is not valid JSON. Do you mean: `["value1", "value2", ..."valueN"]`? – jhericks Jun 02 '12 at 22:49
  • Yes, something like `[{"description1":"value1","name1":"name_"},{"description2":"value2","name2":"name_"},....]` but I always end up getting `{"nameOfTheEntity":[{"description1":"value1","name1":"name_"},{"description2":"value2","name2":"name_"},....]}` – Ayaz Pasha Jun 04 '12 at 11:26
  • 1
    Is SimplePojo a JAXB annotated pojo? Do you set up a JSONJAXBContext in a @Provider somewhere? – jhericks Jun 04 '12 at 19:07
  • @jhericks - Could you please let me know how to make my SimplePojo JAXB annotated? – Ayaz Pasha Jun 06 '12 at 09:27

2 Answers2

12

You can define your service method as follows, using Person POJO:

@GET
@Produces("application/json")
@Path("/list")
public String getList(){
    List<Person> persons = new ArrayList<>();
    persons.add(new Person("1", "2"));
    persons.add(new Person("3", "4"));
    persons.add(new Person("5", "6"));
    // takes advantage to toString() implementation to format as [a, b, c]
    return persons.toString();
}

The POJO class:

@XmlRootElement
public class Person {
    @XmlElement(name="fn")
    String fn;

    @XmlElement(name="ln")
    String ln;

    public Person(){        
    }

    public Person(String fn, String ln) {
        this.fn = fn;
        this.ln = ln;
    }    

    @Override
    public String toString(){
        try {
            // takes advantage of toString() implementation to format {"a":"b"}
            return new JSONObject().put("fn", fn).put("ln", ln).toString();
        } catch (JSONException e) {
            return null;
        }
    }
}

The results will look like:

[{"fn":"1","ln":"2"}, {"fn":"3","ln":"4"}, {"fn":"5","ln":"6"}]
tavi
  • 660
  • 7
  • 16
  • 4
    Improving the answer. With the solution above we have to override the **toString** method in every model class, hence the other solution I found out is [here, click me](http://stackoverflow.com/questions/2199453/how-can-i-customize-serialization-of-a-list-of-jaxb-objects-to-json). We are replacing the JAXB JSON serializer with a better behaved JSON serializer such as Jackson. With this solution we don't have to modify all the model classes which are exposed as REST services. With very little configuration change and customizing `MessageBodyWriter` class of Jersey will do. – Ayaz Pasha Jul 13 '12 at 15:03
3

To return the entries in array-type style, you should build your entity from array. Try the following:

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON})
public Response getSomeList() {
    List<com.abc.def.rest.model.SimplePojo> yourListInstance = 
          new List<com.abc.def.rest.model.SimplePojo>();
    /* 
          Do something
    */
    return Response.ok(yourListInstance.toArray()).build();
}

if you face some trouble according to return type of toArray() method - you could explicitly cast your array:

Response
   .ok((com.abc.def.rest.model.SimplePojo[])yourListInstance.toArray())
   .build(); 

UPD: try to convert your list to JSONArray:

JSONArray arr = new JSONArray();
for (SimplePojo p : yourListInstance) {
  arr.add(p);
}

and then:

Response.ok(arr).build(); 
Alex Stybaev
  • 4,623
  • 3
  • 30
  • 44
  • For the change `return Response.ok(listOfPojos.toArray()).build();` I get the error `SEVERE: A message body writer for Java class [Ljava.lang.Object;, and Java type class [Ljava.lang.Object;, and MIME media type application/json was not found` – Ayaz Pasha Jun 04 '12 at 13:35
  • you need to add `jersey-json` to your classpath – Alex Stybaev Jun 04 '12 at 13:46
  • For the change `Response.ok((com.abc.def.rest.model.SimplePojo[])yourListInstance.toArray()) .build();` I get `com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.abc.def.rest.model.SimplePojo;` – Ayaz Pasha Jun 04 '12 at 13:49
  • I get this error `SEVERE: A message body writer for Java class org.json.JSONArray, and Java type class org.json.JSONArray, and MIME media type application/json was not found` for the changes specified above. – Ayaz Pasha Jun 06 '12 at 09:02
  • once again: you need to add `jersey-json` lib to your classpath. – Alex Stybaev Jun 06 '12 at 10:14
  • All the required libraries including `jersey-json.jar` are available in my classpath. – Ayaz Pasha Jun 06 '12 at 15:28