0

I'm using @RepositoryRestResource to create my REST API, that avoids having to manually write the code as in @RestController, and gives me a nice HATEOAS response. However now the validations I added to my entity don't work, or rather I get the 500 response code instead of 400.

I tried using @ControllerAdvice + @ExceptionHandler to capture the ConstraintViolationException, however it seems that it's being captured before and what's thrown is a TransactionSystemException.

Validating the data is something pretty basic, and yet for some reason after much googling I haven't found a solution.

edit: To show the code:

@ControllerAdvice
public class ConstraintViolationExceptionHandler extends  ResponseEntityExceptionHandler {

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

          return new ResponseEntity<Object>("test 123", HttpStatus.BAD_REQUEST);
    }
}

I still get:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction] with root cause javax.validation.ConstraintViolationException

So it seems the ConstraintViolationException is being captured earlier by Spring Data REST and a TransactionSystemException is thrown. If I change the code to capture this exception like:

@ControllerAdvice
public class ConstraintViolationExceptionHandler extends  ResponseEntityExceptionHandler {

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

          return new ResponseEntity<Object>("test 123", HttpStatus.BAD_REQUEST);
    }
}

Then it works, but this is not the exception I should be capturing.

3
  • See baeldung.com/spring-data-rest-validators Commented Jan 28, 2020 at 9:20
  • Hi Kaladin, Need to look at your code, as per my understanding you doing ok by using excpetion handler... only scenario I could think of ... you must handling ConstraintViolationException or its parent somewhere in your code Commented Jan 28, 2020 at 9:33
  • Hi Swarit Agarwal, I updated the question. It seems that the exception is being captured and converted by Spring Data REST. Commented Jan 28, 2020 at 11:46

2 Answers 2

4

You can handle ConstraintViolationException by ControllerAdvice, I have tried and it works fine, Please find below code snippets for Reference.

User.java

@Entity
@Getter
@Setter

public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String name;

@NotNull
private String surname;
}

UserRepository.java

@RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {
}

GlobalExceptionHandler.java

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<?> handlerException(ConstraintViolationException e) {
        final List<Object> errors = new ArrayList<>();
        e.getConstraintViolations().stream().forEach(fieldError -> {
            Map<String, Object> error = new HashMap<>();
            error.put("path", String.valueOf(fieldError.getPropertyPath()));
            error.put("messgae", fieldError.getMessage());
            errors.add(error);
        });
        HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
        Map<String, Object> body = new HashMap<>();
        body.put("error", errors);
        return new ResponseEntity<>(body, httpStatus);
    }
}

I have used the map for the response body, you can use customize objects as per requirements.

Then try below CURL to test API.

curl --location --request POST 'http://localhost:8080/users' \
--header 'Content-Type: application/json' \
--data-raw '{}'

The response will look like.

Status: 400 BAD REQUEST
{"error":[{"path":"surname","messgae":"must not be null"},{"path":"name","messgae":"must not be null"}]}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, using your example worked, so I reviewed my code. When using GenerationType.AUTO the ExceptionHandler was not executed (using postgres). Changing it to GenerationType.IDENTITY fixed it.
-1

Spring Data REST provides a RepositoryRestExceptionHandler which contains a ResponseEntity<RepositoryConstraintViolationExceptionMessage> handleRepositoryConstraintViolationException(RepositoryConstraintViolationException o_O) method.

The RepositoryRestMvcConfiguration class provides a bean for such an exception handler. If you want to modify it, try providing your own bean and registering it with the configuration. You can do this by, for example, implementing the RepositoryRestConfigurer as you should be familiar from other Spring projects (Spring Security, ...).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.