Как отследить нарушения hibernate / jpa в Spring Boot? - PullRequest
0 голосов
/ 04 ноября 2018

Мне не удалось поймать ConstraintViolationException (или DataIntegrityViolationException) в ResponseEntityExceptionHandler. Я хотел бы вернуть ошибку jpa (например, какое ограничение нарушено) в ответе. (Я предпочитаю не использовать @Valid для параметра метода и ловить handleMethodArgumentNotValid).

...
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.dao.DataIntegrityViolationException;

@ControllerAdvice
public class PstExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler({ConstraintViolationException.class})
    public ResponseEntity<Object> handleConstraintViolation(
        ConstraintViolationException ex, WebRequest request) {

        ...

        return new ResponseEntity<Object>(...);
    }
}

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class Student {

    @Id
    private Long id;

    @NotNull
    private String name;

    @NotNull
    @Size(min=7, message="Passport should have at least 7 characters")
    private String passportNumber;

    public Student() {
    }

...

}

@RequestMapping(value = "/addstudent"...)
@ResponseBody
public ResponseEntity<Object> addStudent(@RequestBody StudentDto studentDto) {

    Student student = new Student();
    student.setId(studentDto.getId());                          // 1L
    student.setName(studentDto.getName());                      // "helen"
    student.setPassportNumber(studentDto.getPassportNumber());  // "321"

    studentRepository.save(student);

    return ResponseEntity.accepted().body(student);
}

спасибо ...

Ответы [ 4 ]

0 голосов
/ 09 августа 2019

У меня была такая же проблема, поэтому мне пришлось перехватить исключение JDBCException:

@ExceptionHandler({JDBCException.class})
public ResponseEntity<Object> handleConstraintViolation(TransactionSystemException ex, WebRequest request) {

    if (ex.getCause() instanceof ConstraintViolationException) {
        ...
    }   

    return new ResponseEntity<Object>(...);
}
0 голосов
/ 21 ноября 2018

Есть 3 способа:

  1. @Valid \ @Validated аннотации.

    Как только они используются на уровне параметров, нарушения становятся доступными через реализации типа Errors \ BindingResult.

  2. ConstraintViolationException генерируется каждый раз, когда объект в недопустимом состоянии передается в .save() или .persist() Методы гибернации.

  3. Объекты могут быть проверены вручную с помощью введенного метода LocalValidatorFactoryBean.validate(). Нарушения ограничения затем доступны через переданную реализацию объекта Errors. Как именно аннотации @Valid \ @Validated реализованы внутри.

0 голосов
/ 27 июля 2019

Вы не можете перехватить ConstraintViolationException.class, поскольку он не распространяется на этот уровень вашего кода, он перехватывается нижними уровнями, переносится и перебрасывается под другим типом. Таким образом, исключение, которое попадает на ваш веб-слой, не является ConstraintViolationException. Таким образом, вы можете сделать что-то вроде этого:

@ExceptionHandler({TransactionSystemException.class})
protected ResponseEntity<Object> handlePersistenceException(final Exception ex, final WebRequest request) {
    logger.info(ex.getClass().getName());
    //
    Throwable cause = ((TransactionSystemException) ex).getRootCause();
    if (cause instanceof ConstraintViolationException) {        

        ConstraintViolationException consEx= (ConstraintViolationException) cause;
        final List<String> errors = new ArrayList<String>();
        for (final ConstraintViolation<?> violation : consEx.getConstraintViolations()) {
            errors.add(violation.getPropertyPath() + ": " + violation.getMessage());
        }

        final ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, consEx.getLocalizedMessage(), errors);
        return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
    }
    final ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), "error occurred");
    return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
0 голосов
/ 21 ноября 2018

Исключения, такие как ConstraintViolationException, не принимаются во внимание, поскольку они выходят из HibernateException. Вы можете посмотреть исключений в методе конвертации , что они включены в исключения Hibernate.

@ExceptionHandler({TransactionSystemException.class})
public ResponseEntity<Object> handleConstraintViolation(TransactionSystemException ex, WebRequest request) {

    if (ex.getCause() instanceof RollbackException) {
       RollbackException rollbackException = (RollbackException) ex.getCause();
         if (rollbackException.getCause() instanceof ConstraintViolationException) {
             return new ResponseEntity<Object>(...);
         }
    ...
    }
    ...

    return new ResponseEntity<Object>(...);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...