ConstraintViolationException in spring rest

后端 未结 2 2181
走了就别回头了
走了就别回头了 2021-01-18 15:36

I have next spring rest controller for handle my exception:

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
pub         


        
相关标签:
2条回答
  • 2021-01-18 15:51

    Try to reproduce next steps:

    • Add to your WebConfiguration file
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
    
    • mark your Controller with @Validated

    • Mark your paramater in Controller's method with

    @Pattern(regexp = "\\d+") @RequestParam String param

    • Then just call that method with parameter like "Some string without digits".


    If you want to use that Entity. Do something like

    @Valid @RequestBody Device device 
    

    in your method. And you can skip all previous steps.

    0 讨论(0)
  • 2021-01-18 15:57

    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)

    0 讨论(0)
提交回复
热议问题