Reputation: 73
I have a Spring Boot server that listens on endpoint. I accept @RequestBody
as an object:
class Body {
private String name;
}
I want it to accept requests like:
{
"name": "some_name"
}
However, it also accepts:
{
"name": "some_name",
"dummy key":"dummy key value"
}
In that case I want it to throw error. How can I achieve it?
Upvotes: 4
Views: 4085
Reputation: 1730
When configuring Spring's handling of unknown properties (fields) in JSON request body, the following are used in combination:
Global level property (application.properties):
spring.jackson.deserialization.fail-on-unknown-properties=true/false
Class level annotation (respective entity class):
@JsonIgnoreProperties(ignoreUnknown=false/true)
spring.jackson.deserialization.fail-on-unknown-properties
)If set to true
, any field(s) in the JSON payload that do not have a corresponding field in the Java entity class, will throw an exception.
For instance, a POST request to your endpoint with the following JSON body will result in client getting the response - 400 BAD REQUEST:
{
"name": "some_name",
"dummy key":"dummy key value"
}
If set to false
(default behaviour), any extra fields are simply ignored.
@JsonIgnoreProperties
annotation (over entity class)ignoreUnknown=false
: An exception will be thrown if there are any fields in the JSON payload that do not correspond to fields in the Java class.ignoreUnknown=true
: Extra fields are simply ignored.Logically you should be able to set the global property in application.properties
and use @JsonIgnoreProperties
annotation to override this for classes you want to make an exception.
However, as of Spring 4.1, the default global property is set to false
(was set to true
in older versions) and it cannot be overridden with @JsonIgnoreProperties(ignoreUnknown = false)
at the class level.
This means that Spring will continue ignoring extra fields in JSON request body even if you annotate the class with
@JsonIgnoreProperties(ignoreUnknown=false)
unless you configure the global default behaviour.
Option 1:
spring.jackson.deserialization.fail-on-unknown-properties=true
in application.properties
.@JsonIgnoreProperties(ignoreUnknown=true)
.Option 2:
@Configuration
class, add the following bean:
@Bean
public Jackson2ObjectMapperBuilder mapperBuilder() {
return new Jackson2ObjectMapperBuilder().failOnUnknownProperties(true);
}
spring.jackson.deserialization.fail-on-unknown-properties=true
.@JsonIgnoreProperties(ignoreUnknown=true)
.Upvotes: 1
Reputation: 478
You can do this in the controller when saving:
@PostMapping("/add")
public ResponseEntity<Body> registerUser(@Valid @RequestBody Body saveUser) {
Body createdUser = userService.save(saveUser);
return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
}
When Spring finds an argument annotated with @Valid, it automatically validates the argument and throws an exception if the validation fails.
Or you can add this in the application.properties
:
spring.jackson.deserialization.fail-on-unknown-properties=true
This helps us to make deserialization fail on unknown properties and throw an exception which we can handle using handleHttpMessageNotReadable
.
Create controller advice to handle exceptions:
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
return new ResponseEntity("Your Response Object",
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Upvotes: 2
Reputation: 738
If you want the controller to return an error when the RequestBody
does not match what you are expecting it is enough to add this to your application.properties
:
spring.jackson.deserialization.fail-on-unknown-properties=true
This will return a default 400 response on malformed requests.
@Valid
annotationAdding the @Valid
annotation to your controller performs constraint validation and it will only fail when, for example, you mark a field as to be of a maximum value of 1
but the request tries to set it to 2
. As per the docs:
Marks a property, method parameter or method return type for validation cascading. Constraints defined on the object and its properties are validated when the property, method parameter or method return type is validated.
But since you are not using any of the tools provided by jakarta.validation
this annotation will have no effect on your code.
Upvotes: 2