O que está acontecendo pessoal é o seguinte.
Estou usando o HibernateTransactionInterceptor para gerenciar as transações do hibernate no Vraptor,
porém quando acontece uma exception(ie. ConstraintViolationException) não consigo recupera-la para tratar na camada de cima.
Gostaria de saber se tem alguma forma de fazer isto, ou algum workaround
Você está usando o hibernate/jpa controlado manualmente ou pelo Vraptor?
Uma coisa que você pode fazer, que fiz algo semelhente em um componente que faz um exception-handler, é verificar se é uma exception do bean validator e tratá-la de forma diferente. Não sei bem o motivo, mas as exceptions do bean validator são um pouco diferentes.
[code] final List messages = new LinkedList();
final Throwable cause = ExceptionUtils.getRootCause(e);
[ERROR] [2010-02-22 17:20:16,806] [http-8080-1] (JDBCExceptionReporter.java:101) - Duplicate entry '1503' for key 'PRIMARY'
[ERROR] [2010-02-22 17:20:16,810] [http-8080-1] (AbstractFlushingEventListener.java:324) - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:46)
at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:46)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59)
at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62)
at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)
at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55)
at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:636)
Caused by: java.sql.BatchUpdateException: Duplicate entry '1503' for key 'PRIMARY'
at com.mysql.jdbc.ServerPreparedStatement.executeBatch(ServerPreparedStatement.java:657)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 37 more
Meu interceptor não está pegando a exception, dei uma olhada no código do HibernateCustomProvider e só tem try e finally.
Lucas, você sabe qual componente do Vrpator está entubando esta exceção?
pessoal o seguinte consegui fazendo uma adaptação, tive que reescrever o HibernateTransactionInterceptor,
inserindo o bloco do catch e incluindo o result para responder as minhas necessidades.
@Intercepts
public class HibernateTransactionInterceptor implements Interceptor {
private final Session session;
private final Result result;
public HibernateTransactionInterceptor(Session session,Result result) {
this.session = session;
this.result = result;
}
public void intercept(InterceptorStack stack, ResourceMethod method,
Object instance) throws InterceptionException {
Transaction transaction = null;
try {
transaction = session.beginTransaction();
stack.next(method, instance);
transaction.commit();
} catch (Exception e) {
Throwable cause = ExceptionUtils.getCause(e);
if (cause instanceof BatchUpdateException){
this.result.use(Results.http()).setStatusCode(409);
}
}
finally {
if (transaction != null && transaction.isActive()) {
transaction.rollback();
}
}
}
public boolean accepts(ResourceMethod method) {
return true; // Will intercept all requests
}
}
e Escrevi um CustomProvider para implementar o meu HibernateTransactionInterceptor.
O ideal é sempre deixar para fazer o log em sua camada mais externa, senão quando der uma exception você terá muitos stacktrace para um mesmo erro, dificultando a visualização dos logs. A menos, claro, que você trate essa exception; nesse caso é melhor fazer o logging dela e depois tratar. (Como é o caso dele “setar o status”)