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 и пользовательский подход к исключениям.