'Strange behaviour of the exception handler on spring boot RestControllerAdvice handleExceptionInternal

Trying to save 2 times the same barcode card the method saveBarcodecard (left side image) throw the error: SQLIntegrityConstraintViolationException: "Duplicate entry '1-*****-EAN13' for key 'fcs_barcodecards.UK4ComplexKey" that I was expected to be intercepted by the method: handleExceptionInternal meant to handler ALL the Exceptions that are not specifically custom implemented but not.

Please note that: SQLIntegrityConstraintViolationException extends ... extends ... Exception

I need to implement a custom handler handleSQLIntegrityConstraintViolationException (please see the image 2 below -green-) to solve this issue.

My simple question is: how come this? :)

Many thanks in advance for your answers, if any :)

enter image 1

enter image description here

@Service
public class FcsBarcodecardServiceImpl implements FcsBarcodecardService {

    @Autowired
    FcsBarcodecardRepository fcsBarcodecardRepository;
    
    @Autowired
    private FcsClientRepository fcsClientRepository;

    @Autowired
    private FcsBarcodecardMapper fcsBarcodecardMapper;

    @Override
    public FcsBarcodecardResponse saveBarcodecard(Long clientId, FcsBarcodecard fcsBarcodecard) {
        
        Optional<FcsClient> fcsClient = fcsClientRepository.findById(clientId);
        
        if (!fcsClient.isPresent()) {
            throw new UsernameNotFoundException("This client do not exists!");
        }
        
        fcsBarcodecard.setFcsClient(fcsClient.get());
        
        return fcsBarcodecardMapper
                .fromFcsBarcodecardToFcsBarcodecardResponse(
                        fcsBarcodecardRepository.save(fcsBarcodecard));
    }

}

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private static final String VALIDATION_ERROR_CHECK_ERRORS_FIELD_FOR_DETAILS = "Validation error. Check 'errors' field for details.";

    /**
     * Predefined: A single place to customize the response body of all exception
     * types.
     */
    @Override
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<Object> handleExceptionInternal(Exception exception, Object body, HttpHeaders headers,
            HttpStatus status, WebRequest request) {
        return buildErrorResponse(exception, FCS_EALLTYPES500, status, request);
    }
    
    
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<Object> handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException ex,
            WebRequest request) {
        return buildErrorResponse(ex, FCS_EALLTYPES500, HttpStatus.INTERNAL_SERVER_ERROR, request);
    }


Solution 1:[1]

ResponseEntityExceptionHandler#handleExceptionInternal() is a place to customize the response body of only those exception types that are handled by an @ExceptionHandler defined in ResponseEntityExceptionHandler. As of the latest Spring version those are

@ExceptionHandler({
        HttpRequestMethodNotSupportedException.class,
        HttpMediaTypeNotSupportedException.class,
        HttpMediaTypeNotAcceptableException.class,
        MissingPathVariableException.class,
        MissingServletRequestParameterException.class,
        ServletRequestBindingException.class,
        ConversionNotSupportedException.class,
        TypeMismatchException.class,
        HttpMessageNotReadableException.class,
        HttpMessageNotWritableException.class,
        MethodArgumentNotValidException.class,
        MissingServletRequestPartException.class,
        BindException.class,
        NoHandlerFoundException.class,
        AsyncRequestTimeoutException.class
    })

Obviously your SQLIntegrityConstraintViolationException is not among them and requires a separate exception handler to be caught and processed by.

If you'd like to have a single place to handle any expection, you'd have to specifically define an exception handler with e.g. @ExceptionHandler(Exception.class)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dekkard