问题
I am replacing manual validation of input to a POST request in a Spring Boot REST-controller. JSR-303 Spring Bean Validation is used for validating the instance variables in the request body and this is working as expected. What is the recommended method to validate that the object in the request body is not null?
I have tried:
annotating the entire object such as this: @NotNull @Valid @RequestBody Foo foo
annotating the entire class with @NotNull
I am replacing:
@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@RequestBody Foo foo, ...) {
if(foo == null) {
return (new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}
}
with a Bean Validation equivalent:
@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@Valid @RequestBody Foo foo, ...) {
...
}
I tried unit testing the controller method by:
// Arrange
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mockMvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
I expected a MethodArgumentNotValidException which is handled by a @ControllerAdvice for this exception, but I get HttpMessageNotReadableException when executing the unit test. My questions:
- is it necessary to test if the request body is null?
- if 1. is true, how should this be done with Bean Validation?
回答1:
Seeing your code, you already check if the body is null. In fact @RequestBody
has a default parameter required
which defaults to true. So no need for Bean validation for that !
Your main issue here seems to be in your test. First of all it is good to write a test to validate your endpoint behavior on null.
However, in your test you does not pass null. You try to create a Json object from a null
value with your objectMapper
.
The object you are writting seems not to be a valid json. So when your sending this body, Spring says that it cannot read the message, aka the body of your request, as you say it is a application/json
content but there is not json in it.
To test null body, just send your request in your test just removing the .content(requestBody)
line and it should work !
--- Edit 1 I thought it was rejecting the message because of the body, but in fact it seems to work right away for me. Here is my controler and test so you can compare to your full code :
@RestController()
@RequestMapping("end_point")
public class TestController {
@PostMapping
public ResponseEntity<Map<String, Object>> editFoo(@RequestBody Foo foo) {
// if(foo == null) {
// return (new ResponseEntity<>(new HashMap<>(), HttpStatus.BAD_REQUEST));
// }
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class TestControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@Test
public void test_body_is_null() throws Exception {
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
}
}
This was made using Spring Boot 2.1.6.RELEASE
--- Edit 2 For the record if you want to use validation for null here, here is a snippet of the controller :
@RestController()
@RequestMapping("end_point")
@Validated
public class TestController {
@PostMapping
public ResponseEntity<Map<String, Object>> editFoo(@NotNull @RequestBody(required = false) Foo foo) {
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
First you have to set required to false for the body, as default is true. Then you have to add the @NotNull
annotation on the request body and @Validated
on the controller.
Here if you launch your test you will see that the request fails with :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: editFoo.foo: must not be null
As you said you had a @ControllerAdvice
you can then map the exception as you wish !
来源:https://stackoverflow.com/questions/57038083/validating-if-request-body-in-http-post-request-is-null-in-spring-boot-controlle