Yunz
Yunz

Reputation: 251

Spring Boot validation message not shown

I have a Spring Boot application (with version 2.4.5) as a Kotlin project. Now when I enter something invalid, I get an error message, but not my error message that I set in the annotation.

Controller

  @PostMapping(value = ["/seatMap/save"])
    fun addSeatPlan(@RequestPart @Valid data: DSeatMap, @RequestPart image: MultipartFile?, auth: AuthenticationToken) {
        try {
            if (data.uuid == null) {
                seatService.addSeatMap(auth.organisation!!, data, image)
            } else {
                seatService.updateSeatMap(data, auth.organisation!!, image)
            }
        } catch (e: UnauthorizedException) {
            throw e
        }
    }

Data class

import java.util.*
import javax.validation.constraints.NotEmpty

data class DSeatMap(
    var uuid: UUID?,
    @field:NotEmpty(message = "name is empty")
    val name: String,
    var data: String,
    val quantity: Int,
    var settings: DSettings?
)

My Response, here should be message = "name is empty"

{
  "timestamp": "2021-04-22T19:47:08.194+00:00",
  "status": 400,
  "error": "Bad Request",
  "message": "Validation failed for object='data'. Error count: 1",
}

If I set the property it shows me the correct one but I don't want to have all the side information I only want to output the message

server.error.include-binding-errors=always

Result:

{
  "timestamp": "2021-04-22T19:56:30.058+00:00",
  "status": 400,
  "error": "Bad Request",
  "message": "Validation failed for object='data'. Error count: 1",
  "errors": [
    {
      "codes": [
        "NotEmpty.data.name",
        "NotEmpty.name",
        "NotEmpty.java.lang.String",
        "NotEmpty"
      ],
      "arguments": [
        {
          "codes": [
            "data.name",
            "name"
          ],
          "arguments": null,
          "defaultMessage": "name",
          "code": "name"
        }
      ],
      "defaultMessage": "name is empty",
      "objectName": "data",
      "field": "name",
      "rejectedValue": "",
      "bindingFailure": false,
      "code": "NotEmpty"
    }
  ],
  "path": "/api/dashboard/seatMap/save"
}

Upvotes: 8

Views: 14408

Answers (4)

Bilal
Bilal

Reputation: 1382

Please here you can find an optimised solution :

@ControllerAdvice
public class ControllerAdvisor extends ResponseEntityExceptionHandler {
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        var errors = new HashMap<>();
        for (var err : ex.getBindingResult().getAllErrors()) 
            errors.put(((FieldError) err).getField(), err.getDefaultMessage());
        

        return this.handleExceptionInternal(ex, errors, headers, status, request);
    }
}

Upvotes: 0

user20407231
user20407231

Reputation: 11

Please create the following ControllerAdvice with the corresponding ExceptionHandler. Should be something like this:

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return errors;
    }
}

In the recent Spring Boot versions, the sending of error messages was disabled, and now needs to be manually implemented like shown above.

Reference: https://www.baeldung.com/spring-boot-bean-validation#the-exceptionhandler-annotation

Upvotes: 1

Yunz
Yunz

Reputation: 251

Ok finally I found a solution. I created a global exception handler that listens to the MethodArgumentNotValidException. After that I manipulate the message and set the validation message that I set before in the annotation

@RestControllerAdvice
class ExceptionControllerAdvice {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException::class)
    fun handleValidationExceptions(ex: MethodArgumentNotValidException): Map<String, String?>? {
        val errors: MutableMap<String, String?> = HashMap()
        ex.bindingResult.allErrors.forEach { error: ObjectError ->
            val fieldName = (error as FieldError).field
            val errorMessage = error.getDefaultMessage()
            errors[fieldName] = errorMessage
        }
        return errors
    }

}

Source: https://www.baeldung.com/spring-boot-bean-validation

Upvotes: 6

sham
sham

Reputation: 452

@Yunz I think the "errors" attribute gets added to your response since you set server.error.include-binding-errors=always can you try setting that to never or don't define this property and rely on default(which is never).

you need to set the server.error.include-message=always since version 2.3, Spring Boot hides the message field in the response to avoid leaking sensitive information; we can use this property with an always value to enable it

for details check out the spring boot documentation:

Upvotes: 6

Related Questions