Hibernatevalidation失败时出现意外的UnsupportedOperationException

为什么我在validation失败时从Hibernate获得UnsupportedOperationException? 我希望有一个ConstraintViolationException。

下面是我的DAO。 当它通过validation时,它工作正常。 我正在使用Hibernate和Hibernate Validator 4.我正在使用Websphere 8.0。 我认为WebSphereExtendedJtaPlatform是罪魁祸首,但我不知道为什么。

如果我看一下所谓的WebSphereExtendedJtaPlatform的源代码(跟随源代码的链接),看起来大多数方法只会抛出UnsupportedOperationException。

http://grepcode.com/file/repo1.maven.org/maven2/org.hibernate/hibernate-core/4.0.0.CR1/org/hibernate/service/jta/platform/internal/WebSphereExtendedJtaPlatform.java

这是我的堆栈跟踪:

org.hibernate.AssertionFailure  HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in com.westfieldgrp.beanvalidation.persistence.Car entry (don't flush the Session after an exception occurs) [11/14/12 16:48:48:785 EST] 00000020 RegisteredSyn E WTRN0074E: Exception caught from before_completion synchronization operation: java.lang.UnsupportedOperationException at org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform$TransactionManagerAdapter.setRollbackOnly(WebSphereExtendedJtaPlatform.java:139) 

我的堆栈跟踪中另一个有趣的片段:

 Entity manager factory name (src_persistence) is already registered. If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name' 

这是class级

 package com.westfieldgrp.pom.data.dao; import java.util.ArrayList; import java.util.Set; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.RollbackException; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import com.westfieldgrp.beanvalidation.persistence.Car; import com.westfieldgrp.beanvalidation.persistence.Driver; import com.westfieldgrp.beanvalidation.persistence.Person; public class CarDAO { private EntityManager entityManager; public void save(Person convertedPerson, Driver convertedDriver, Car convertedCar, FacesContext facesContext) throws ConstraintViolationException{ EntityManager em = getEntityManager(); //em.setFlushMode(FlushModeType.COMMIT); if("test".equals(convertedPerson.getName())){ // To test JPA validation convertedPerson.setName(null); } //Person savedPerson = em.merge(convertedPerson); try { //em.merge(convertedPerson); em.persist(convertedPerson); em.flush(); } catch (Exception e) { System.out.println("*******" + getRootCause(e)); } } private String getRootCause(Throwable e){ if(e.getCause() != null){ return getRootCause(e.getCause()); } else { return e.toString(); } } public EntityManager getEntityManager() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("src_persistence"); entityManager = emf.createEntityManager(); return entityManager; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } } 

人物实体:

 package com.westfieldgrp.beanvalidation.persistence; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import org.hibernate.validator.constraints.Length; /** * The persistent class for the PERSON database table. * */ @Entity @Table(name="PERSON") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="PERSON_ID") private int personId; @Column(name="NAME") @NotNull(message = "A name is required.") //@Length(min = 5, message = "Need a longer name.") private String name; @Column(name="EMAIL") @NotNull(message = "An email is required.") //@Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email format.") private String email; public Person() { } public int getPersonId() { return this.personId; } public void setPersonId(int personId) { this.personId = personId; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } } 

整个堆栈跟踪:

 [11/14/12 19:00:53:202 EST] 0000003c EntityManager Z org.hibernate.ejb.internal.EntityManagerFactoryRegistry addEntityManagerFactory HHH000436: Entity manager factory name (src_persistence) is already registered. If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name' [11/14/12 19:00:53:214 EST] 0000003c SystemOut O *******java.lang.UnsupportedOperationException [11/14/12 19:00:53:214 EST] 0000003c AssertionFail Z org.hibernate.AssertionFailure  HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in com.westfieldgrp.beanvalidation.persistence.Person entry (don't flush the Session after an exception occurs) [11/14/12 19:00:53:215 EST] 0000003c RegisteredSyn E WTRN0074E: Exception caught from before_completion synchronization operation: java.lang.UnsupportedOperationException at org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform$TransactionManagerAdapter.setRollbackOnly(WebSphereExtendedJtaPlatform.java:139) at org.hibernate.engine.transaction.internal.jta.CMTTransaction.markRollbackOnly(CMTTransaction.java:131) at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.setRollbackOnly(TransactionCoordinatorImpl.java:305) at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.setRollbackOnly(SynchronizationCallbackCoordinatorImpl.java:118) at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.beforeCompletion(SynchronizationCallbackCoordinatorImpl.java:108) at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:53) at org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform$TransactionManagerAdapter$TransactionAdapter$1.invoke(WebSphereExtendedJtaPlatform.java:176) at $Proxy56.beforeCompletion(Unknown Source) at com.ibm.ws.jtaextensions.SynchronizationCallbackWrapper.beforeCompletion(SynchronizationCallbackWrapper.java:66) at com.ibm.tx.jta.impl.RegisteredSyncs.coreDistributeBefore(RegisteredSyncs.java:291) at com.ibm.ws.tx.jta.RegisteredSyncs.distributeBefore(RegisteredSyncs.java:152) at com.ibm.ws.tx.jta.TransactionImpl.prePrepare(TransactionImpl.java:2332) at com.ibm.ws.tx.jta.TransactionImpl.stage1CommitProcessing(TransactionImpl.java:553) at com.ibm.tx.jta.impl.TransactionImpl.processCommit(TransactionImpl.java:1014) at com.ibm.tx.jta.impl.TransactionImpl.commit(TransactionImpl.java:948) at com.ibm.ws.tx.jta.TranManagerImpl.commit(TranManagerImpl.java:379) at com.ibm.tx.jta.impl.TranManagerSet.commit(TranManagerSet.java:181) at com.ibm.ejs.csi.TranStrategy.commit(TranStrategy.java:922) at com.ibm.ejs.csi.TranStrategy.postInvoke(TranStrategy.java:234) at com.ibm.ejs.csi.TransactionControlImpl.postInvoke(TransactionControlImpl.java:579) at com.ibm.ejs.container.EJSContainer.postInvoke(EJSContainer.java:4755) at com.westfieldgrp.ejb.EJSLocalNSLCarSessionBean_f700c086.save(EJSLocalNSLCarSessionBean_f700c086.java) at com.westfieldgrp.beans.CarBean.processCar(CarBean.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37) at java.lang.reflect.Method.invoke(Method.java:611) at org.apache.el.parser.AstValue.invoke(AstValue.java:262) at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278) at org.apache.myfaces.view.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:83) at javax.faces.component._MethodExpressionToMethodBinding.invoke(_MethodExpressionToMethodBinding.java:88) at org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:100) at javax.faces.component.UICommand.broadcast(UICommand.java:120) at javax.faces.component.UIViewRoot._broadcastAll(UIViewRoot.java:973) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:275) at javax.faces.component.UIViewRoot._process(UIViewRoot.java:1285) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:711) at org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:34) at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:171) at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1147) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:722) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:449) at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178) at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1020) at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87) at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:883) at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1659) at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:195) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:452) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:511) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:305) at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:83) at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165) at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161) at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138) at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204) at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775) at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1648) 

我最终根据以下链接修改了WebSphereExtendedJtaPlatform代码。 我很困惑为什么这个课程基本上没有实施。

https://forum.hibernate.org/viewtopic.php?f=1&t=992310

我在Websphere Liberty 16.0.0.4上遇到了同样的问题,并通过更改persistence.xml解决了这个问题:

  

以下类需要与hibernate库一起位于类路径中:

 package biz.bitech.hibernate.websphere; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import com.ibm.tx.jta.TransactionManagerFactory; import com.ibm.tx.jta.UserTransactionFactory; import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform; public class WebSphereJtaPlatform extends AbstractJtaPlatform { @Override protected TransactionManager locateTransactionManager() { return TransactionManagerFactory.getTransactionManager(); } @Override protected UserTransaction locateUserTransaction() { return UserTransactionFactory.getUserTransaction(); } } 

您可以使用getEntityManager()在每个请求上创建一个新的实体管理器。 您应该请求(例如通过dependency injection)应用程序范围的持久性管理器。

请注意,您正在接收来自hibernate的HHH000099错误。 这是由于GeneratedValue返回null并且当hibernate执行插入时,它会将null传递给您的PK。

我认为你的ID会随表一起自动递增。 将Generated value设置为AUTO / TABLE / IDENTITY时,Hibernate会在表中查找值。 如果坚持表格,这不应该是一个问题。

我遇到了类似的问题,我所做的就是将列设为insertable = false。

希望有所帮助。

下面的代码来自hibernate-core 4.3.7.FINAL(SynchronizationCallbackCoordinatorNonTrackingImpl)

在重新打包和发送exception之前,您将看到对setRollbackOnly的调用,对于WebSphereExtendedJtaPlatform,它只会抛出一个不受支持的操作exception,这是您在日志中看到的。 此时,由于您从未达到重新打包运行时exception的程度,因此它将丢失。

但不知何故,hibernate设法将其记录到stdout,因此您将在SystemOut.log文件中找到SQLexception

 @Override public void beforeCompletion() { LOG.trace( "Transaction before completion callback" ); if ( !transactionCoordinator.isActive() ) { return; } boolean flush; try { final int status = transactionCoordinator.getTransactionContext().getTransactionEnvironment() .getJtaPlatform().getCurrentStatus(); flush = managedFlushChecker.shouldDoManagedFlush( transactionCoordinator, status ); } catch ( SystemException se ) { setRollbackOnly(); throw exceptionMapper.mapStatusCheckFailure( "could not determine transaction status in beforeCompletion()", se ); } try { if ( flush ) { LOG.trace( "Automatically flushing session" ); transactionCoordinator.getTransactionContext().managedFlush(); } } catch ( RuntimeException re ) { setRollbackOnly(); throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re ); } finally { transactionCoordinator.sendBeforeTransactionCompletionNotifications( null ); transactionCoordinator.getTransactionContext().beforeTransactionCompletion( null ); } }