春季休息时出现ConstraintViolationException [英] ConstraintViolationException in spring rest

查看:326
本文介绍了春季休息时出现ConstraintViolationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

我的实体类:

  @Entity 
公共类设备{

@Id
@Column(name =name ,nullable = false)
私有字符串名称;

@Column(name =send_date)
@NotNull
private日期sendDate;
}

我尝试模拟 ConstraintViolationException 控制器我使用下一个代码:

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

结果我收到下一个异常:

< blockquote>

[dispatcherServlet]:? - Servlet.service()用于servlet
[dispatcherServlet]与path []的上下文引发异常[Request
处理失败;嵌套异常是
org.springframework.transaction.TransactionSystemException:无法
提交JPA事务;嵌套异常是
javax.persistence.RollbackException:在提交
事务时发生错误,并且引发了根本原因
javax.validation.ConstraintViolationException:
类的验证失败[com.entity.Device ]
更新时间[javax.validation.groups.Default,]列出
约束违规:[
ConstraintViolationImpl {interpolatedMessage ='可能不为null',
propertyPath = sendDate,rootBeanClass = class
com.entity.Device,
messageTemplate ='{javax.validation.constraints.Nstracks.NotNull.message}'}]

因此,从堆栈跟踪中可以看到,我首先收到 TransactionSystemException ,因此我的ExceptionHandler方法( hiberAnnotationExceptionHandler )不会调用。所以我的问题是如何模拟这个异常( ConstraintViolationException )?
在此先感谢。

解决方案

TransactionSystemException的原因


  1. Hibernate实体管理器负责抛出所有hibernate异常

如果你进入代码 AbstractEntityManagerImpl.convert()方法,
您会看到默认情况下它不处理任何特定的异常,如ConstraintViolation,而只是抛出并包装在PersistenceException中。


  1. 如果您在@Transaction中调用您的代码并转换为TransactionSystemException,JPA事务管理器会捕获上述异常,您可以看到Spring JPA事务的代码manager class =org.springframework.orm.jpa.JpaTransactionManager

正确解决您的异常问题的解决方案


  1. 首先注册JPA方言, HibernateExceptions并在你的事务管理器bean中封装到特定的spring异常中。




 < bean id =transactionManagerclass = org.springframework.orm.jpa.JpaTransactionManager> 
< property name =entityManagerFactoryref =entityManagerFactory/>
< property name =jpaDialectref =jpaDialect/>
< / bean>

< bean id =jpaDialectclass =org.springframework.orm.jpa.vendor.HibernateJpaDialect/>


HibernateJpaDialect会捕获这些异常并将其转换为特定于Spring的异常, / p>


  if(ex instanceof ConstraintViolationException){
ConstraintViolationException jdbcEx =(ConstraintViolationException)ex;
return new DataIntegrityViolationException(ex.getMessage()+; SQL [+ jdbcEx.getSQL()+
]; constraint [+ jdbcEx.getConstraintName()+],ex);
}





  1. 您还可以注册您的entitymanager正在使用hibernate jpaVendorAdapter来完成您在任何地方使用hibernate。




 < bean id =entityManagerFactoryclass =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean> 
< property name =packagesToScanvalue =com.pack.model/>
< property name =persistenceUnitManagerref =persistenceUnitManager/>
< property name =persistenceUnitNamevalue =entityManager/>
< property name =jpaVendorAdapterref =jpaVendorAdapter/>
< / bean> < bean id =jpaVendorAdapterclass =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter/>





  1. 现在在您的控制器中,您可能会遇到dataIntegrityException,该异常来自因ConstraintViolationException引发的hibernate方言




@ExceptionHandler (DataIntegrityViolationException.class)


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.

解决方案

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)

这篇关于春季休息时出现ConstraintViolationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆