Как я могу убедиться, что исключения во время синтаксического анализа приводят к тому же виду ответа, что и (пользовательский) ответ, возвращаемый для ошибок проверки? - PullRequest
0 голосов
/ 20 сентября 2018

Я использую Spring для создания API, но у меня возникли некоторые проблемы с введением настраиваемого отчета об ошибках (части) проверки тела запроса.

При возникновении ошибок синтаксического анализа / проверки,Я хочу дать пользовательский ответ пользователю.
Это хорошо работает для полей, помеченных @Valid, наряду с валидаторами, такими как @javax.validation.constraints.NotNull, с использованием пользовательского ResponseEntityExceptionHandler, помеченного @ControllerAdvice.
.однако не работает, если при синтаксическом анализе тела запроса генерируется исключение (еще до того, как проверки пройдут).В этом случае я получаю html страницу ошибки со статусом 500 (Server Error)

Как я могу убедиться, что исключения во время синтаксического анализа приводят к тому же типу ответа, что и (пользовательский), который я возвращаю для ошибок проверки?


Код моей конечной точки выглядит следующим образом:

@RequestMapping(value= "/endpoint"
    produces = { "application/json" }, 
    consumes = { "application/json" },
    method = RequestMethod.POST)
default ResponseEntity<Object> postSomething(@Valid @RequestBody MyRequestBody requestData){
    // ...
}

Класс MyRequestBody выглядит следующим образом:

@Validated
public class MyRequestData {

    @JsonProperty("stringValue")
    private String stringValue = null;

    @NotNull
    @Valid
    public String getStringValue() {
        return stringValue;
    }

    // ...

    public enum EnumValueEnum {
        VALUE_1("value 1"),
        VALUE_1("value 2");

        private String value;

        EnumValueEnum(String value) {
            this.value = value;
        }

        @Override
        @JsonValue
        public String toString() {
            return String.valueOf(value);
        }

        @JsonCreator
        public static EnumValueEnum fromValue(String text) {
          if(text == null){
            return null;
          }
          for (EnumValueEnum b : EnumValueEnum.values()){
            if (String.valueOf(b.value).equals(text)) {
              return b;
            }
          }
          throw new HttpMessageNotReadableException("EnumValueEnum \"" + text + "\" does not exist");
        }

    }

    @JsonProperty("enumValue")
    private EnumValueEnum enumValue = null;
}

Пользовательская обработка ошибок проверки (и отчетность) выглядит следующим образом:

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class MyValidationHandler extends ResponseEntityExceptionHandler {
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // return status(BAD_REQUEST).body(new ValidationResponse(ex.getBindingResult().getFieldErrors()));
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // return status(BAD_REQUEST).body(new ValidationResponse((JsonMappingException) ex.getCause()));
    }
}

В этом коде, если пользователь отправляет запрос с несуществующим значением перечисления, генерируется исключение HttpMessageNotReadableException.Я хотел бы поймать это где-нибудь и заменить его пользовательским ответом, который согласуется с другой обработкой исключений, которую я делаю.Где / Как я могу это сделать?

1 Ответ

0 голосов
/ 21 сентября 2018

Я нашел решение моей собственной проблемы.

Вы можете использовать обычную обработку исключений Spring MVC:

Если аннотировать метод с помощью @ExceptionHandler, Spring будетпопытайтесь использовать его для обработки исключений для указанного типа исключения (в поле значения аннотации или в аргументе метода).Этот метод может быть помещен в контроллер или даже в ResponseEntityExceptionHandler, который я использую для другой обработки ответа проверки.

@ExceptionHandler
public ResponseEntity handle(HttpMessageConversionException e){
    // return status(BAD_REQUEST).body(new ValidationResponse((JsonMappingException) e.getCause()));
}

Определите, какой тип исключения вы обрабатываете:

Подвох здесьбыло то, что исключение, выдаваемое при разборе, заключено в (некоторый подтип) в JsonMappingException, который, в свою очередь, снова заключен в HttpMessageConversionException.

e instanceof HttpMessageConversionException
e.getCause() instanceof JsonMappingException
e.getCause().getCause() // == your original exception

@ExceptionHandler должен для этого принять HttpMessageConversionExceptionвместо первоначально выданного исключения (которое в моем случае было HttpMessageNotReadableException)

Это не будет работать, если вы напишите @ExceptionHandler, который принимает только ваше оригинальное исключение!

...