Recuperar exception a partir do HibernateTransactionInterceptor

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 :smiley:

Abraços

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);

        if (cause instanceof ConstraintViolationException) {
            ConstraintViolationException constrains = (ConstraintViolationException) cause;
            for (ConstraintViolation<?> cv : constrains.getConstraintViolations()) {
                String msg = cv.getRootBeanClass().getSimpleName() + "." + cv.getPropertyPath() + " " + cv.getMessage();
                messages.add(new ValidationMessage(msg, "error"));
            }
        } else {
            messages.add(new ValidationMessage(cause.getMessage(), "error"));
        }[/code]

Fala garcia-jj ;p

Então cara estou usando o hibernate controlado pelo HibernateCustonProvider.
O problema é que não sei onde implementar essa verificação?

editado: Meu problema é que como estou usando o customprovider ele não me gera exception e passa direto so exibindo no log.

Você criou um interceptor específico?

gostei muito da dica,

obrigado e Abraços;

cria um interceptor:

@Intercepts
public class ConstraintViolationInterception implements Interceptor {
   accepts(method) {
      return true;
   }

   intercept(stack, method, instance) {
       try {
          stack.next(method, instance);
       } catch(exception) {
            // o código que o garcia postou
       }
   }
}
[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?

ou eu to perdido demais :wink:

Abraços.

dá um try…catch em InterceptorException e usa o e.getCause pra saber qual exceção foi

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 que vocês acham? resolveu meu problema.

Abraços.

só toma cuidado que vc tá engolindo a exceção… faça o seguinte, dentro do catch:

 Throwable cause = ExceptionUtils.getCause(e);  
 if (cause instanceof BatchUpdateException){  
     this.result.use(Results.http()).setStatusCode(409);  
 } else {
    throw new InterceptorException(cause);
 }

de resto tá ok =)

alem de setar o status, é bom logar a exception…

Show do milhão !

nem me dei conta que estava entubando a exceção.

Valeu Lucas Abraços.

editado:

Paulo,

a exception já é logada automaticamente, acho que pelo próprio transaction.commit(); quando ele quebra.
mas só por garantia vou logar também.

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”)