VRaptor - Interceptando recursos anotados

25 respostas
C

Olá, estou desenvolvendo uma aplicação para estudos com VRaptor e segui esse guia no cookbook (http://vraptor.caelum.com.br/pt/cookbook/interceptando-recursos-anotados/), porém, msm sem a anotação @Transacional em meu método, o mesmo continua abrindo/fechando transações.

Eu deveria fazer mais alguma coisa para ele parar de realizar esse tipo de operação ? Ou seja, só abrir e fechar as transações quando o método tiver a anotação @Transacional ?

Obrigado.

25 Respostas

Rafael_Guerreiro

Você trocou o método accepts para esse aqui??

É nesse método que contém a lógica para interceptar ou não.

public boolean accepts(ResourceMethod method) { return method .getMethod() //metodo anotado .isAnnotationPresent(Transactional.class) || method .getResource() //ou recurso anotado .getType() .isAnnotationPresent(Transactional.class); }

C

Sim, o problema é nos métodos que não tem o @Transacional, pq mesmo ele retornando false no accepts, ele está abrindo e fechando a conexão no início e no final de todos os métodos, o que eu não quero.

Tanto, que se eu colocar @Transacional em algum método, ele me dá erro falando que a conexão já está ativa quando ele passa no intercept.

Então, o que eu não entendo, é que msm com o Interceptor ele continua abrindo e fechando as conexões em todos os métodos, e é isso que eu quero evitar.

Rafael_Guerreiro

Essas transações são iniciadas no próprio interceptor ou você tem algum outro lugar que as inicia?

Lembre-se que abrir transação é diferente de abrir sessão.

C

Sim, com certeza é diferente ! Mas pelo que entendi, antes de criar o Interceptor, o VRaptor trata essas transações para mim correto ? Sempre abrindo e fechando no início e final dos métodos.

Por exemplo:

public teste(Object o){ // Nesse caso msm sem a transação, ele faz transacao.begin(); dao.adiciona(o); // E depois transacao.commit(); }

Como eu desabilito isso para ele fazer somente quando tiver a anotação @Transacional ? Quero que dê erro no dao.adiciona falando que não tem transação !! rsrs

Rafael_Guerreiro

Desse jeito mesmo. Me mostra o seu interceptor…

E o seu controller.

C

O fonte está em casa, mas o interceptor está rigorosamente igual ao do cookbook. E o controller é igual o adiciona que fiz acima, só que no caso é inserção de usuário igual a FJ21.

Só com o interceptor, ele já deveria parar de abrir e fechar conexões sozinho ? E respeitar minha anotação ? Ou teria que fazer algo mais para “desabilitar” isso ?

Rafael_Guerreiro

É… Só mudando o método accepts para esse novo formato que já funciona…

C

Hmmm, msm com o interceptor ele continua abrindo e fechando conexões em todos meus métodos, msm sem a anotação.

Rafael_Guerreiro

Bom, depois você me mostra essas duas classes…

Faça um debug e veja se ele está retornando true no método accepts, se estiver, é por que ele encontrou a anotação, ai você pode ter anotado algum lugar errado…

C

Quando eu coloco a anotação ele está retornando TRUE certinho. O meu problema é que mesmo os métodos que não tem anotação estão abrindo e fechando a transação, mesmo o accepts retornando FALSE !! Logo, não é meu interceptor que está abrindo e fechando ela, é outra coisa, pq nesse caso de retornar FALSE ele nem entra no intercepts, e é essa outra coisa que eu queria fazer parar, entendeu ?

G

Provavelmente o interceptor padrão do vraptor, que abre a transação sempre, ainda está ativo. Você precisa desativa-lo não usando o pacote br.com.caelum.vraptor.util.hiberante/jpa.

Outra solução é alterar teu componente para sobrescrever o padrão do vraptor:

C

[quote=garcia-jj]Provavelmente o interceptor padrão do vraptor, que abre a transação sempre, ainda está ativo. Você precisa desativa-lo não usando o pacote br.com.caelum.vraptor.util.hiberante/jpa.

Outra solução é alterar teu componente para sobrescrever o padrão do vraptor:

Obrigado, acredito que seja isso mesmo… vou testar a noite e retorno !! Se não me engano, coloco algo sobre esse pacote no web.xml em alguma config mesmo…

C

É, não funcionou, rsrs... vou postar minhas classes... (Só lembrando que uso JPA)

Interceptor
@Intercepts
public class TransactionInterceptor implements Interceptor {

	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.METHOD, ElementType.TYPE })
	public @interface Transactional {
	}

	private EntityTransaction utx = null;

	public TransactionInterceptor(EntityManager em) {
		this.utx = em.getTransaction();
	}

	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object instance) {
		try {
			utx.begin();
			stack.next(method, instance);
			utx.commit();
		} finally {
			if (utx.isActive()) {
				utx.rollback();
			}
		}
	}

	public boolean accepts(ResourceMethod method) {
		return method.getMethod().isAnnotationPresent(Transactional.class)
				|| method.getResource().getType()
						.isAnnotationPresent(Transactional.class);
	}

}
Método do Controller
@Post("/usuarios")
	public void adiciona(Usuario usuario) {
		if (dao.existeUsuario(usuario)) {
			validator.add(new ValidationMessage("Login já existe",
					"usuario.login"));
		}
		validator.onErrorUsePageOf(UsuariosController.class).novo();
		dao.adicionar(usuario);
		result.redirectTo(ProdutosController.class).lista();
	}
Web.xml (Caso sirva de algo)
<!-- config JPA -->
	<context-param>
		<param-name>br.com.caelum.vraptor.packages</param-name>
		<param-value>br.com.caelum.vraptor.util.jpa</param-value>
	</context-param>


	<!-- configura o controlador do VRaptor -->
	<filter>
		<filter-name>vraptor</filter-name>
		<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
	</filter>
Nesse caso, o método adiciona só deveria funcionar se tivesse a anotação @Transactional, porem, msm sem ela, algo está abrindo e fechando a conexão, e é isso que quero evitar...
Lucas_Cavalcanti

vc tem que tirar esse pacote:

<context-param>  
        <param-name>br.com.caelum.vraptor.packages</param-name>  
        <param-value>br.com.caelum.vraptor.util.jpa</param-value>  
    </context-param>

ele é quem está abrindo e fechando a transação. Só que vc teria que fazer os componentFactory’s de EntityManager e EntityManagerFactory…

alternativa a isso é manter o pacote da jpa registrado e criar essa classe:

@Component
public class MeuTransactionInterceptor extends JPATransactionInterceptor {
    //sobrescreve o método accepts com a implementação que vc postou
}

daí só precisa do accepts, o intercept já tá implementado.

C

Hmmm eu já tinha tentado isso, mas não rolou... fiz certo né!?

@Intercepts
@Component // nao sei se precisa disso msm, mas como vc colocou no exemplo eu segui
public class TransactionInterceptor extends JPATransactionInterceptor implements
		Interceptor {

	public TransactionInterceptor(EntityManager manager, Validator validator) {
		super(manager, validator);
		this.utx = manager.getTransaction();
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.METHOD, ElementType.TYPE })
	public @interface Transactional {
	}

	private EntityTransaction utx = null;

	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object instance) {
		try {
			System.out.println("intercept");
			utx.begin();
			stack.next(method, instance);
			utx.commit();
		} finally {
			if (utx.isActive()) {
				utx.rollback();
			}
		}
	}

	public boolean accepts(ResourceMethod method) {
		System.out.println("accepts");
		return method.getMethod().isAnnotationPresent(Transactional.class)
				|| method.getResource().getType()
						.isAnnotationPresent(Transactional.class);
	}

}
Ele continua controlando a transação...
C

Eu também tentei apenas criar a classe como vc falou:

@Component
public class MeuTransactionInterceptor extends JPATransactionInterceptor {

	public MeuTransactionInterceptor(EntityManager manager, Validator validator) {
		super(manager, validator);
		System.out.println("MeuTransactionInterceptor");
	}
}
Mas ainda assim, o JPA continua controlando a transação... acho que não entendi algo do que vc disse... poderia explicar melhor ?
Lucas_Cavalcanti

deixa a classe do jeito que eu falei e implementa o accepts!

retorna false no accepts, por exemplo, daí nada vai ficar com transação.

C

Meu web.xml eu não alterei nada... minhas classes ficaram:

@Intercepts
public class TransactionInterceptor implements Interceptor {

	public TransactionInterceptor(EntityManager manager) {
		this.utx = manager.getTransaction();
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.METHOD, ElementType.TYPE })
	public @interface Transactional {
	}

	private EntityTransaction utx = null;

	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object instance) {
		try {
			utx.begin();
			stack.next(method, instance);
			utx.commit();
		} finally {
			if (utx.isActive()) {
				utx.rollback();
			}
		}
	}

	public boolean accepts(ResourceMethod method) {
		return method.getMethod().isAnnotationPresent(Transactional.class)
				|| method.getResource().getType()
						.isAnnotationPresent(Transactional.class);
	}

}
@Component
public class MeuTransactionInterceptor extends JPATransactionInterceptor {

	public MeuTransactionInterceptor(EntityManager manager, Validator validator) {
		super(manager, validator);
	}

	public boolean accepts(ResourceMethod method) {
		return false;
	}

}
Certo? Mas não ta rolando... ele nem passa pelo accepts...
Lucas_Cavalcanti

então tira o pacote da jpa do web.xml… e recria as componentFactories… o interceptor deveria funcionar… ele não passa nem pelo construtor?

C

21:27:22,106 INFO [stdout] (http--127.0.0.1-8080-4) Construtor TransactionInterceptor 21:27:22,108 INFO [stdout] (http--127.0.0.1-8080-4) accepts TransactionInterceptor | Tem anotacao: false | Metodo: novo 21:27:22,120 INFO [stdout] (http--127.0.0.1-8080-4) Construtor MeuTransactionInterceptor 21:27:26,815 INFO [stdout] (http--127.0.0.1-8080-4) Construtor TransactionInterceptor 21:27:26,816 INFO [stdout] (http--127.0.0.1-8080-4) accepts TransactionInterceptor | Tem anotacao: false | Metodo: adiciona 21:27:26,834 INFO [stdout] (http--127.0.0.1-8080-4) Construtor MeuTransactionInterceptor 21:27:27,153 INFO [stdout] (http--127.0.0.1-8080-4) Construtor TransactionInterceptor 21:27:27,153 INFO [stdout] (http--127.0.0.1-8080-4) accepts TransactionInterceptor | Tem anotacao: false | Metodo: lista 21:27:27,156 INFO [stdout] (http--127.0.0.1-8080-4) Construtor MeuTransactionInterceptor
Aparentemente o fluxo ta ok, ele não passa nenhuma vez no intercept pq nenhum método está com a anotação msm… alguma idéia ? Ele continua controlando as transações…

C

Se eu colocar @Intercepts no MeuTransactionInterceptor e implementar Interceptor, ele passa a entrar no accepts, mas mesmo assim o controle de transação continua…

Lucas_Cavalcanti

bom, plano B…
remova a declaração do pacote da jpa e crie essas duas classes:

@Component @ApplicationScoped
public class EMFC extends EntityManagerFactoryCreator {...}

@Component
public class EMC extends EntityManagerCreator {...}
C

Devo mudar algo mais ? Eu criei as 2 classes e removi a configuração do web.xml, e mesmo assim algo continua controlando a transação… rsrsrs

Lucas_Cavalcanti

então dá um clean no seu projeto e no servidor, pq no VRaptor não tem nada que faça esse controle automático sem o pacote registrado…

(ve se vc não tá com algum plugin do vraptor tipo o vraptor-hibernate4)

C

Lucas, foi marcação minha, funcionou sim… obrigado pela ajuda e pelo aprendizado !!

Criado 26 de fevereiro de 2013
Ultima resposta 27 de fev. de 2013
Respostas 25
Participantes 4