Required request body is missing, but it's there

Viewed 985

I have a POST endpoint with a UserStateDTO request body. The Junit test are working fine; however, I cannot make it work from the browser because "Required request body is missing". As you can see the body is there... It's driving me crazy. Please find the error and snippets below.

org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public void .....UserRestController.setState(UserStateDTO)
@PostMapping(value = "/state", consumes = MediaType.APPLICATION_JSON_VALUE)
public void setState(@RequestBody UserStateDTO userStateDTO) {
    if (userStateDTO != UserStateDTO.ACTIVE && userStateDTO != UserStateDTO.DISABLED) {
        throw new BusinessException(GeneralErrors.INVALID_REQUEST);
    }
    UserDTO userDTO = userService.getUser();
    userDTO.setState(userStateDTO);
    userService.updateUser(userDTO);
}
public enum UserStateDTO {
    ACTIVE("ACTIVE"),
    DISABLED("DISABLED");

    private final String state;

    private static final Map<String, UserStateDTO> states = new HashMap<>();

    UserStateDTO(String state) {
        this.state = state;
    }

    static {
        for (UserStateDTO u : UserStateDTO.values()) {
            states.put(u.getValue(), u);
        }
    }

    @JsonValue
    public String getValue() {
        return state;
    }

    @JsonCreator
    public static UserStateDTO fromValue(String state) {
        return states.get(StringUtils.upperCase(state));
    }

}

fetch("http://localhost:4200/user/state", {
  "headers": {
    "accept": "application/json, text/plain, */*",
    "accept-language": "en,hu;q=0.9,nb;q=0.8",
    "content-type": "application/json",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin",
    "x-xsrf-token": "-"
  },
  "referrer": "http://localhost:4200/",
  "referrerPolicy": "strict-origin-when-cross-origin",
  "body": "{\"state\":\"ACTIVE\"}",
  "method": "POST",
  "mode": "cors",
  "credentials": "include"
});
2 Answers

You have to add getState() method inside your enum. Correct code below:

public enum UserStateDTO {
  ACTIVE("ACTIVE"),
  DISABLED("DISABLED");

  private final String state;

  private static final Map<String, UserStateDTO> states = new HashMap<>();

  UserStateDTO (String state) {
    this.state = state;
  }

  static {
    for (UserStateDTO u : UserStateDTO.values()) {
        states.put(u.getValue(), u);
    }
  }

  public String getState() {
    return state;
  }

  @JsonValue
  public String getValue() {
    return state;
  }

  @JsonCreator
  public static UserStateDTO fromValue(String state) {
    return states.get(StringUtils.upperCase(state));
  }
}

Or you can add just inside method fromValue() annotation @JsonProperty("state"), which bind your request body value without getter. Correct method below:

  @JsonCreator
  public static UserStateDTO fromValue(@JsonProperty("state") String state) {
    return states.get(StringUtils.upperCase(state));
  }

Hello and welcome to stackoverflow.

Here is a solution for your problem. You should use a class that have an attribute state of type UserStateDTO since your request is {"state" : "ACTIVE"}

Create a new class named UserStateWrapperDto

public class UserStateWrapperDto {

    private UserStateDTO state;

    public UserStateDTO getState() {
        return state;
    }

    public void setState(UserStateDTO state) {
        this.state = state;
    }
}

Then changes your controller method to get a param of type UserStateWrapperDto

    @PostMapping(value = "/state", consumes = MediaType.APPLICATION_JSON_VALUE)
    public void setState(@RequestBody UserStateWrapperDto userStateWrapperDTO) {
        if (userStateWrapperDTO.getState() != UserStateDTO.ACTIVE && userStateWrapperDTO.getState()  != UserStateDTO.DISABLED) {
            throw new BusinessException(GeneralErrors.INVALID_REQUEST);
        }
       UserDTO userDTO = userService.getUser();
        userDTO.setState(userStateDTO.getState());
        userService.updateUser(userDTO);
    }
}

Consume your webservice with this request :

{
    "state" : "ACTIVE"
}

Thanks

Related