1

I have a Spring 4.3.3 @RestController which manages an entity type via Lists.

@RestController
@RequestMapping("...")
public class EntityRestController {
    @PostMapping
    public void doSomeWork(@RequestBody final List<Entity> entities) { ... }
}

I discovered sometimes I may receive a request where the body consists not of an array, but a single JSON object. I'm using Gson as the default serializer/deserializer and obviously it throws an exception.

JSON parse error: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT

What would the better way to tackle this problem be (at the Controller level)?

LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • Could you do something alone the lines of habing a different mapping for a SINGLE entity and just executing the other one after converting that one object to a list? – Zachary Craig Jul 16 '18 at 14:16
  • @zack6849 Unfortunately I cannot control the caller request URL as of now. So I have to work solely on this controller. – LppEdd Jul 16 '18 at 14:17
  • does spring let you overload post mappings so you can have different methods depending on whih mapping it matches? – Zachary Craig Jul 16 '18 at 14:19
  • 1
    @zack6849 Actually you cannot overload a RequestMapping method without modifying its URL. It will throw an "ambiguous mapping" exception. – LppEdd Jul 16 '18 at 14:24

1 Answers1

0

You could use HttpServletRequest in method parameter, like:

@RestController
@RequestMapping("...")
public class EntityRestController {
    @PostMapping
    public void doSomeWork(HttpServletRequest request) {
        // Do your things here..
    }
}

And this question has many answers how to parse request body within HttpServletRequest:

  1. Use apache commons-IO : IOUtils.toString(request.getReader()).
  2. Use request.getParameterMap() :

    Map<String, String[]> map = request.getParameterMap();
    for(String paramName : map.keySet()) {
        String[] paramValues = map.get(paramName);
    
        for(String valueOfParam : paramValues) {
            // Do your things..
        }
    }
    

Or other techniques based on your need and preferences.

HTH

xsalefter
  • 640
  • 5
  • 16
  • 1
    It's going to work for sure, but I'd prefer a cleaner solution if possible. – LppEdd Jul 16 '18 at 14:29
  • 1
    You could just accept an `Object` and introspect it to see what the object is a type of then map it within the controller but unless you differentiate the endpoints there isn't really anything cleaner. – Darren Forsythe Jul 16 '18 at 14:30
  • @LppEdd as you mentioned in other comments, other cleaner solution would lead to ambiguous mapping exception. Think on this way: If you think there's a cleaner approach, what object that should be used in the Controller's method parameter? – xsalefter Jul 16 '18 at 14:35
  • A Filter which wraps the HttpServletRequest (and modifies the getReader() method) might be an optimal solution as it can be applied to multiple URL and registered using Java configuration – LppEdd Jul 16 '18 at 14:51