Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConstraintViolationException in spring rest

I have next spring rest controller for handle my exception:

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody
ExceptionResponseDTO hiberAnnotationExceptionHandler(ConstraintViolationException exception) {
    return  new ExceptionResponseDTO("Entity is null or we are out of range!", exception.getMessage(), ExceptionMapper.INSTANCE.exceptionToExceptionDTO(exception));
}

My entity class:

@Entity
public class Device {

    @Id
    @Column(name="name", nullable = false)
    private String Name;

    @Column(name = "send_date")
    @NotNull
    private Date sendDate;
}

I try to emulate ConstraintViolationException, so in my controller I use next code:

Device d = new Device();
d.setName("sdsdsd");
d.setSendDate(null);
deviceRepository.save(d);

And as result I receive next exception:

[dispatcherServlet]:? - 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: Validation failed for classes [com.entity.Device] during update time for groups [javax.validation.groups.Default, ] List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=sendDate, rootBeanClass=class com.entity.Device, messageTemplate='{javax.validation.constraints.NotNull.message}'} ]

So as you can see from stacktrace I receive TransactionSystemException first and because of this my ExceptionHandler method (hiberAnnotationExceptionHandler) doesn't call. So my question is how to emulate this exception (ConstraintViolationException)? Thanks in advance.

like image 854
Iurii Avatar asked Aug 17 '15 13:08

Iurii


People also ask

What is ConstraintViolationException in Java?

Exception thrown when an action would violate a constraint on repository structure. For example, when an attempt is made to persistently add an item to a node that would violate that node's node type.

What is ConstraintViolationException in hibernate?

hibernate. exception. ConstraintViolationException. This is by far the most common cause of DataIntegrityViolationException being thrown – the Hibernate ConstraintViolationException indicates that the operation has violated a database integrity constraint.

How do I send a custom error message in REST API spring boot?

The most basic way of returning an error message from a REST API is to use the @ResponseStatus annotation. We can add the error message in the annotation's reason field. Although we can only return a generic error message, we can specify exception-specific error messages.


1 Answers

Reason for TransactionSystemException

  1. Hibernate entity manager is responsible for throwing all hibernate exceptions

If you go inside the code AbstractEntityManagerImpl.convert() method, you will see that by default it's not handling any specific exception like ConstraintViolation instead it just throws and wraps in PersistenceException.

  1. JPA transaction manager catches the above exception if you are calling your code inside @Transaction and converts to TransactionSystemException,you can see the code of spring JPA transaction manager class="org.springframework.orm.jpa.JpaTransactionManager"

Solution for correctly resolving your exception

  1. First register a JPA dialect which can intercept those HibernateExceptions and wrap into specific spring exceptions like this in your transaction manager bean.
 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="jpaDialect" ref="jpaDialect"/>
</bean>

<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

HibernateJpaDialect catches those exception and converts to spring specific exceptions like this

if (ex instanceof ConstraintViolationException) {
          ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
          return new DataIntegrityViolationException(ex.getMessage()  + "; SQL [" + jdbcEx.getSQL() +
                  "]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
      }
  1. You can also register that your entitymanager is using hibernate jpaVendorAdapter to be complete that your using hibernate everywhere.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="packagesToScan" value="com.pack.model" />
        <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
        <property name="persistenceUnitName" value="entityManager"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    </bean>    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
  1. Now in your controller you can expect dataIntegrityException which came from hibernate dialect which is thrown because of ConstraintViolationException

@ExceptionHandler(DataIntegrityViolationException.class)

like image 138
Anudeep Gade Avatar answered Sep 21 '22 15:09

Anudeep Gade