3

I want to handle json request for List of Object and Object it self in the same Spring controller. Below is the exact example.

Json Request for Single Object:

{"data":{"prop":"123456","prop2":"123456"}}

Json Request for List of Objects:

{"data":[{"prop":"123456","prop2":"123456"},{"prop":"123456","prop2":"123456"}]}

My Controller is as follow.

@PostMapping(path="/path")
public @ResponseBody String getSomething(@RequestBody Input data){
     return service.getSomething(data);
}

I want to handle both of this requests in a single spring controller.

Appreciate your help. Thanks.

  • 3
    Why not pass a list each time ? – Arnaud Aug 17 '18 at 08:44
  • can't you add another endpoint in the same controller. It is a best practice to have single endpoint taking a list. even if you are passing one entry – pvpkiran Aug 17 '18 at 08:44
  • I can not pass list each time as the input is coming from another system and also can not add another endpoint as I need to put them in one controller. – Prashant Chindhade Aug 17 '18 at 08:45
  • You will have to manually parse the request as Spring has no way to determine how to map either a single or multiple variable in JSON if they are going to the same URL. – M. Deinum Aug 17 '18 at 08:50
  • Maybe you could take the body as a `String` then use answers from here : https://stackoverflow.com/questions/9817315/how-to-check-whether-the-given-object-is-object-or-array-in-json-string – Arnaud Aug 17 '18 at 08:52

3 Answers3

1

Its been some time. However I was facing the same issue and was thinking whether any solution is there The below worked for me

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Data> data;
BJ5
  • 512
  • 6
  • 22
0

EDIT

You can create DTOs for your inputs but receive the @RequestBody as a JSON string and then parse it as a list or a single object request.

DTO for a request list:

public class InputDataList {

private List<Input> data;

// getters and setters
}

DTO for a single request object:

public class InputDataSingle {

private Input data;

// getters and setters
}

Then on your controller:

        @PostMapping(path="/path")
        public @ResponseBody String getSomething(@RequestBody String json){

    // this is better done in a service but for simplicity, I write it in the controller
    try {
    InputDataSingle data = new ObjectMapper().readValue(json, InputDataSingle.class);
    // If fails to parse as a single object, parse as a list
    } catch (Exception) (
    InputDataList data = new ObjectMapper().readValue(json, InputDataList.class);
             }
// handle objects in the service layer
        }
Urosh T.
  • 3,336
  • 5
  • 34
  • 42
  • I have edited the answer. Basically, you just handle that logic inside your service and build your response string there with a `StringBuilder` or a `json`, dependiing on the use case. – Urosh T. Aug 17 '18 at 10:01
  • This will be true only if you are sending List all the time. I also need to send single object without list. How could i handle that in this controller itself ? – Prashant Chindhade Aug 17 '18 at 10:04
  • If the json structure you have described for a single object is like this: `{"data":{"prop":"123456","prop2":"123456"}}`, then the controller will work. Feel free to test. – Urosh T. Aug 17 '18 at 10:06
  • I have this structure only. I tested the same. As you see the request is not in list in the case of Single Object request. – Prashant Chindhade Aug 17 '18 at 10:51
  • You are correct, sorry for wasting your time, I haven't seen the missing `[ ]` brackets. In that case, you have to treat the body as a `String` and then try to parse a `json` or a `List` in your service. I think that someone in the comments have mentioned something already. I will edit my answer if I get a working solution – Urosh T. Aug 17 '18 at 11:22
  • For service layer I have already implemented the solution. I need to handle both requests on the same controller if possible. – Prashant Chindhade Aug 20 '18 at 07:21
  • @PrashantChindhade, I have edited the answer, take a look – Urosh T. Aug 20 '18 at 07:35
-1

Sorry, Really not a good workaround (solution), because it is not kind of misleading and poor for maintainability, secondly not good at all to keep code in the catch block and this is violating the coding principles.

I would highly suggest splitting 2 endpoints one for single i.e (/something) and another for list (/something-batch)

AbuSaad
  • 1
  • 1
  • 2
    This looks more like a comment to [this answer](https://stackoverflow.com/a/51891717/2227743) rather than a new answer. – Eric Aya Apr 19 '22 at 14:02