Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey, how to POST a list of JSON objects?

I am building a RESTful web-service in Java using Jersey 1.11, and have problems implementing a method which consumes a list of JSON-ised entities. The single instance method works fine.

The error I get is:

Status 400 - Bad Request. The request sent by the client was syntactically incorrect.

My method signature looks like this:

@POST
@Path("/some-path/{someParam}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String createBatch(List<MyEntity> myEnts, @PathParam("someParam") String someParam)
{
   ... 
}

The JSON I am sending in the requests is an array of MyEntity JSON objects:

[{"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]

Similar questions have been asked before and one straight forward suggestion was to change the consumed media type to text and de-serialize the JSON manually but I'd prefer a cleaner solution.

Is the JSON I am sending even valid in this context or do I need a top-level {} i.e a wrapper entity? This would also seem a bit un-natural.

Thank you,

/David

like image 998
OG Dude Avatar asked Mar 24 '13 00:03

OG Dude


People also ask

How do I pass a list of objects in JSON?

Put a key/value pair in the JSONObject, where the value will be a JSONArray which is produced from a Collection. But it puts JSON representation of your object as String. So you should use either JSONArrays or Java objects. You should not mix them.

Can JSON be a list of objects?

JSON defines only two data structures: objects and arrays. An object is a set of name-value pairs, and an array is a list of values. JSON defines seven value types: string, number, object, array, true, false, and null.

How do I send a JSON response to a jersey?

Jersey endpoints and return a JSON responseCreate a few endpoints in Jersey, and Jackson will handle the object from/to JSON conversion. 4.1 Create the following endpoints and return JSON response. GET /json/ , returns a JSON string. GET /json/{name} , returns an User object containg the {name} in JSON string.

Does Jersey use Jackson?

Jersey uses Jackson internally to convert Java objects to JSON and vice versa.


3 Answers

The problem is the generic list type, which is not available at runtime due to type erasure, so Jersey wont know what kind of POJOs to unmarshal.

I think the simplest solution (which I know works, at least when using Jackson in your MessageBodyReader) in this case would be to just use a normal Java array instead of the List, so the method signature becomes:

public String createBatch(@PathParam("someParam") String someParam, MyEntity[] myEnts)

And yes, combining @PathParam and a consumed/unmarshalled body parameter should be fine.

like image 159
David Avatar answered Oct 07 '22 13:10

David


I think PathParam and also a Param which should unmarshalled by Jersey(JAX-RS) is not possible. Please try to remove the PathParam Parameter.

And if you need the second Parameter so create a new class like this

@XmlRootElement(name = "example")
public class Example {
  @XmlElement(name = "param")
  private String param;
  @XmlElement(name = "entities")
  private List<MyEntity> entities;
}

and also modify your Methode :

@POST
@Path("/some-path")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String createBatch(Example example)
{
   ... 
}

your JSON Should look like this:

{
 "param":"someParam",
 "entities":[
   {"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]
}
like image 43
Zelldon Avatar answered Oct 07 '22 13:10

Zelldon


Ok, so in the end I solved this using a simple wrapper class in order to generate { items : [{ <myEnityInstanceJson1> }, { <myEnityInstanceJson2> }, ... ]}. I guess there is a way to have a generic wrapper but for now this will do:

@XmlRootElement
public class MyEntityWrapper implements Serializable {

    private static final long serialVersionUID = 1L;

    private List<MyEntity> items;

    public MyEntityWrapper() {
        this.items = new ArrayList<MyEntity>();
    }

    public MyEntityWrapper(List<MyEntity> items) {
        this.items = items;
    }

    public List<MyEntity> getItems() {
        return items;
    }

    public void setItems(List<MyEntity> items) {
        this.items = items;
    }
}
like image 34
OG Dude Avatar answered Oct 07 '22 14:10

OG Dude