Перехват исключений, генерируемых методом репозитория с разными кодами ошибок

java #spring #spring-boot #jpa #spring-data-jpa

#java #весна #весенняя загрузка #jpa #spring-data-jpa

Вопрос:

Есть ли способ перехватить DataAccessException то, что генерируется data-layer ( @Repository ), зная, какой метод вызывает это исключение?

Написание пользовательских SQLExceptionTranslator настроек не соответствует моим потребностям, поскольку я не могу определить, какой метод вызвал исключение.

У меня есть такой репозиторий:

 public interface UserRepository extends JpaRepository<UserEntity, Integer> {
    @ErrorCode("E1000")
    User findById(int id);
    
    @ErrorCode("E1001")
    User findByUsername(String username);
}
 

ErrorCode это пользовательская аннотация, содержащая код ошибки, который мне нужно отправлять клиенту при DataAccessException каждом возникновении.

Если есть способ перехватить вызов findById с перехватом DataAccessException , то легко извлечь код ошибки из аннотации и повторно создать пользовательское исключение, которое может быть перехвачено обработчиком исключений.

Комментарии:

1. Было бы лучше, если бы мы могли сделать это без Spring AOP.

2. Не могу придумать способ без Spring AOP, поэтому я все же опубликовал ответ с ним на случай, если никто не найдет лучшего подхода.

3. Почему вы не можете определить метод, вызывающий исключение? Это должно быть в stacktrace исключения, которое доступно в SQLExceptionTranslator . Однако при таком подходе существует проблема, поскольку метод, который генерирует исключение, и метод, вызывающий его, могут быть совершенно разными из-за записи JPAS за кешем и отложенной загрузки.

Ответ №1:

Если разрешен Spring AOP, вы можете создать свой собственный аспект, например:

 @Aspect
public class ErrorCodeAspect {

    @Around("@annotation(errorCode)")
    public Object aroundErrorCode(ProceedingJoinPoint joinPoint, ErrorCode errorCode) throws Throwable {
        try {
            return joinPoint.proceed();
        } catch (DataAccessException dae) {
            throw new YourCustomException(errorCode.value(), dae);
        }
    }

}
 

Обратите внимание, что аннотации к методам интерфейса не наследуются при реализации методов класса (даже с @Inherited тем, который применяется только к родительским классам), поэтому вам, вероятно, потребуется вместо этого аннотировать ваши конкретные классы служб для подключения aspect (если Spring не использует дополнительную черную магию с прокси-серверами репозитория, о которых я бы не знал).

Ответ №2:

Вы можете определить пользовательский ExceptionHandler .

 @RestControllerAdvice
public class RestExceptionResolver {
    @ExceptionHandler(DataAccessException.class)
    public ResponseEntity<String> handleNoSuchElementException(DataAccessException ex) {
        return ResponseEntity.status(yourErrorCode);
    }
}
 

Комментарии:

1. Как мне получить yourErrorCode ?

2. О, я понимаю. Вам нужно получить код ошибки, который объявлен как аннотация. Тогда, я думаю, вам нужно использовать Spring AOP и пользовательский подход к исключениям.