0

this problem has me crazy and I don't know where to look anymore.

I have a rest api that receives a @RequestBody DTO

public ResponseEntity<JuntaCalificadoraDTO> edit(@Valid @RequestBody JuntaCalificadoraDTO juntaCalifDTO) {
......

This is the DTO that I receive and that I validate with java bean validations. Generate getter and setters with lombok

@Data
@NoArgsConstructor
public class JuntaCalificadoraDTO extends RepresentationModel<JuntaCalificadoraDTO> {

    private Long id_process;

    @NotNull @Min(1) @Positive
    private Integer presidentJC;

    @NotNull @Min(1) @Positive
    private Integer secretaryJC;

    @NotNull @Min(1) @Positive
    private Integer representativeFuncJC;

}

Java bean validations does its job. It is valid that it is not zero, its minimum and also that it is positive. The problem is that it does not validate when I pass a letter to a variable, for example:

{
    "id_process": 4455,
    "presidentJC": "dd",
    "secretaryJC": 33,
    "representativeFuncJC": 3
}

It detects the error, and postman returns "400 Bad Request" but nothing else. Also the Intellij console doesn't show anything, no stack.

I need to catch that error which I imagine is a "NumberFormatException" but I haven't been able to. And I don't know why he hides it. I created a method in a @ControllerAdvice class but no success either.

    @ExceptionHandler (value = {NumberFormatException.class})
    public final ResponseEntity<Object> invalidNumberHandling(NumberFormatException ex) {
        
        ApiError apiError = ApiError.builder()
                .timestamp(LocalDateTime.now())
                .status(HttpStatus.BAD_REQUEST)
                .message("Number Format Exception")
                .errors(List.of("El o los parámetros de entrada no son válidos"))
                .details(ex.getMessage())
                .build();

        return new ResponseEntity<>(apiError, apiError.getStatus());

    }

I will appreciate any guidance. And sorry for my bad english

brujita
  • 31
  • 3
  • Before wondering why you can't catch some particular exception, what's your justification for thinking that anything ever raises that exception? Surely if there are validators, it is documented what happens when a value fails validation? – dangling else May 20 '22 at 01:28
  • It is basic that if an integer receives a text string an exception occurs. And here it is, because the service returns a 400 error. The problem is that I can't capture it in order to deliver an appropriate descriptive message to the client that will consume it. – brujita May 20 '22 at 14:28

1 Answers1

1

You are close. It's actually an InvalidFormatException that is wrapped into a HttpMessageNotReadableException.

By catching the InvalidFormatException you have access to the field that failed and to the wrong value, so it should be enough for you create a meaningful response to the user.

See this sample application (Java 17) in case you have any doubts - if this doesn't work please let me know your Spring Boot version.


@SpringBootApplication
public class SO72312634 {

    public static void main(String[] args) {
        SpringApplication.run(SO72312634.class, args);
    }

    @Controller
    static class MyController {

        @PostMapping
        public ResponseEntity<?> edit(@Valid @RequestBody JuntaCalificadoraDTO juntaCalifDTO) {
            return ResponseEntity.ok().build();
        }
    }

    @Bean
    ApplicationRunner runner() {
        return args -> new RestTemplate().exchange(RequestEntity
                    .post("http://localhost:8080")
                    .contentType(MediaType.APPLICATION_JSON)
                    .body("""
                             {
                                "id_process": 4455,
                                "presidentJC": "ds",
                                "secretaryJC": "abc",
                                "representativeFuncJC": 3
                            }
                            """), String.class);
    }

    @ControllerAdvice
    static class ExceptionAdvice {

        @ExceptionHandler(value = InvalidFormatException.class)
        public final ResponseEntity<Object> httpMessageNotReadable(InvalidFormatException ex) {
            String failedPaths = ex.getPath().stream().map(JsonMappingException.Reference::getFieldName).collect(Collectors.joining());
            return new ResponseEntity<>("Field %s has invalid value %s ".formatted(failedPaths, ex.getValue()), HttpStatus.BAD_REQUEST);
        }
    }

    @Data
    @NoArgsConstructor
    public static class JuntaCalificadoraDTO {

        private Long id_process;

        @NotNull
        @Min(1) @Positive
        private Integer presidentJC;

        @NotNull @Min(1) @Positive
        private Integer secretaryJC;

        @NotNull @Min(1) @Positive
        private Integer representativeFuncJC;

    }

}

Output:

Caused by: org.springframework.web.client.HttpClientErrorException$BadRequest: 400 : "Field presidentJC has invalid value ds "

Tomaz Fernandes
  • 2,429
  • 2
  • 14
  • 18
  • Thanks for your help :). I added the method to my error handling class but it didn't work. I also tried letting it stand alone like you do and it doesn't work either. It still seems very strange to me that the error does not even appear on the stack and it is only that exception, the others catch them well. – brujita May 20 '22 at 13:42
  • What’s your Spring Boot version? Can you post a minimal reproducible example? https://stackoverflow.com/help/minimal-reproducible-example – Tomaz Fernandes May 20 '22 at 13:53
  • Are you using any other projects that could be interfering? Where does this ApiError object come from? – Tomaz Fernandes May 20 '22 at 13:54
  • the ApiError is just a POJO with getter and setter. I ran the method as is as you put it without using my POJO and it didn't work either. – brujita May 20 '22 at 14:25