Search code examples
javaspringspring-mvcjacksonspring-restcontroller

Spring MVC @RestController -> PUTting results in "400 Bad Request" no matter what I do


I have a Spring RestController which works great when I GET data from it, but when I try to PUT the very same data, I get a 400 Bad Request.

Here is the simplest version of my controller that should still work (I left out the GET method):

@RestController
@RequestMapping("/configuration/ledstrips/{name}/display")
public class DisplayController {

    @ResponseBody
    @RequestMapping(method = RequestMethod.PUT, produces = { "application/hal+json" })
    public DisplayResource setDisplay(@PathVariable String name, @RequestBody DisplayResource display) {

        return display;
    }
}

This is the DisplayResource:

public class DisplayResource extends ResourceSupport {

    private List<Color> pixels;

    public List<Color> getPixels() {

        return pixels;
    }


    public void setPixels(List<Color> pixels) {

        this.pixels = pixels;
    }
}

I pretty much copied this code over from another branch, and there it works!

I can't figure it out!

EDIT

Here's the GET-Method:

@ResponseBody
@RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json" })
public DisplayResource getDisplay(@PathVariable String name) {

    LEDStripDTO ledStripDTO;

    try {
        ledStripDTO = ledStripDTOService.getDTO(name);
    } catch (IOException | NullPointerException exception) {
        throw new LoadFailedException("Error loading LED strip:", exception);
    }

    Link self = linkTo(methodOn(DisplayController.class).getDisplay(name)).withSelfRel();

    DisplayResource displayResource = new DisplayResource();

    displayResource.add(self);

    try {
        displayResource.setPixels(ledStripService.getPixels(ledStripDTO));
    } catch (IOException | TimeoutException | AlreadyConnectedException | NotConnectedException exception) {
        throw new LoadFailedException("Error getting Information from LED strip:", exception);
    }

    return displayResource;
}

And a result it produces (for a LED strip of length 1):

{
  "pixels": [
    {
      "red": 0,
      "green": 16,
      "blue": 0
    }
  ],
  "_links": {
    "self": {
      "href": "http://localhost:8080/configuration/ledstrips/devled/display"
    }
  }
}

When I send this, be it with or without the _links segment, I get a 400 error.


Solution

  • As it's a PUT, you've defined a produces but not a consumes. It could be that the endpoint doesn't know what format to expect the body in, which is why it's rejecting it. Try:

    Having looked at the source you've provided, I can see that the Color class has a constructor that requires arguments. The default ObjectMapper provided by the Jackson libraries won't be able to unmarshall a JSON string due to this constructor. Try adding a default constructor to the Color class along side the current one:

    public Color(int red, int green, int blue) {
    
        this.red = setColorLimits(red);
        this.green = setColorLimits(green);
        this.blue = setColorLimits(blue);
    }
    
    public Color() {}