13

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

Community
  • 1
  • 1
OG Dude
  • 936
  • 2
  • 12
  • 22
  • I post same answer on following link .... http://stackoverflow.com/questions/13242414/passing-a-list-of-objects-into-an-mvc-controller-method-using-jquery-ajax/43582662#43582662 – Minhajul Islam Apr 24 '17 at 08:10

5 Answers5

7

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}, ...]
}
Zelldon
  • 5,396
  • 3
  • 34
  • 46
  • I am having the same problem with handling List of objects. I am sending List of objects from client side using axios post and receiving it with Jax RS but I am having 500 internal server error. In your answer you said JSON should be like that but what if JSON is just a list of objects `[{"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]` – JustStartedProgramming Mar 19 '18 at 12:34
  • I think you need a root node like `entities`, What exception is printed in your log? Because you said that you have an 500 Error. – Zelldon Mar 19 '18 at 14:24
  • I have created a root node like `entities` and my list looks like this `[entities:[ {"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]` – JustStartedProgramming Mar 19 '18 at 14:42
  • Server-side no exception and when I tried to debug it not even trigger the POST method – JustStartedProgramming Mar 19 '18 at 14:44
  • here I have asked this question before reading your post [link](https://stackoverflow.com/questions/49323401/sending-post-axios-request-with-array-of-objects) – JustStartedProgramming Mar 19 '18 at 15:23
4

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;
    }
}
OG Dude
  • 936
  • 2
  • 12
  • 22
2

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.

David
  • 1,359
  • 1
  • 13
  • 20
0

This is valid JSON for an array:

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

(see here for an example)

You don't need to send text, you can send it as JSON. Also your MyEntity should have @XmlRootElement on it (see here, section 5.2 for an example).

You don't need PathParam in your arguments, someParam is available when the request is posted if you leave the @Path("/some-path/{someParam}") in your method signature .

Bizmarck
  • 2,663
  • 2
  • 33
  • 48
0

Wrapper class works. MyEntity[] myEnts doesn't work.

This is what I did and it worked.

public String createBatch(@PathParam("someParam") String someParam,
                                                  String content)

Use ObjectMapper to convert to List of objects.

List<MyEntity> entities = om.readValue(content, 
                                       new TypeReference<List<MyEntity>>(){}).
Rob Kielty
  • 7,958
  • 8
  • 39
  • 51
Arun Kumar
  • 39
  • 3