vRaptor + Autowired

29 respostas
el_loko

wood:
Nos exemplos, o que eu tenho visto é um @Component dando um @AutoWired em beans do Spring.

É possível fazer o contrário? A partir de um bean do Spring dar um @AutoWired em @Component’s do VRaptor?

Comigo está acontecendo este erro

Em outro Post, vi que o Lucas informou que não é possível que tenha o listener RequestContextListener no web.xml pois o VRaptor já o declara (2cents, isto deveria estar na documentação).

Boa tarde,

Não sei se entendi direito, mas você está fazendo a injeção via setter, no método setUsuarioDAO, certo?
Qual a versão do VRaptor que você está usando? Pois, acho que à partir da versão 3 a injeção via setter não é mais suportada.

De qualquer forma dá uma olhada nesse tópico: http://www.guj.com.br/java/236664-vraptor–injecao-no-field

29 Respostas

Lucas_Cavalcanti

Olá wood,

a partir da versão 3.3.0 dá pra injetar um bean do spring no vraptor e vice versa,

o erro é por outro motivo:

Error creating bean with name 'usuarioDAOImpl': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton

ou seja, o usuarioDAOImpl é request scoped e vc tá tentando injetá-lo em um bean singleton (ou coisa do tipo)
como o próprio erro sugere, vc pode usar scoped proxies…

anote o setter com:

@Scope(proxyMode=ScopeProxyMode.TARGET_CLASS)

se não funcionar, anote a classe UsuarioDAOImpl com essa anotação, e tudo vai funcionar.

[]'s

Lucas_Cavalcanti

o UsuarioDao não pode ser @RequestScoped então (é o default do VRaptor)

anote o UsuarioDao com @ApplicationScoped (talvez vc tenha que receber SessionFactory ao invés de Session, ou algo do tipo

Lucas_Cavalcanti

o setter está com @Autowired?

Lucas_Cavalcanti

só um detalhe:

se possível use o applicationContext.xml no classpath, sem listeners registrados no web.xml, daí tudo deveria funcionar sem problemas…

X

Wood,

Conseguiu resolver o problema? Estou exatamente com o mesmo cenário…

Aproveitando: Lucas, pra poder usar o spring-security precisamos declarar o filtro do spring. Neste caso, o applicationContext.xml precisa ficar dentro do WEB-INF, e não no classpath… Acha que tem alguma coisa a ver com isto?

Lucas_Cavalcanti

se não me engano dá pra configurar o spring security para usar o applicationContext do classpath…

quais listeners vc está registrando no web.xml?

X

Meu web.xml tem somente:

<listener>
  		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 	</listener>
   
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

A configuração do vraptor tá vindo via web-fragment.xml…

Lucas_Cavalcanti

o problema é q o VRaptor não funciona bem com esse context Loader listener (pq ele faz o mesmo trabalho)… se vc tira o listener, o security não funciona?

X

Não rola… ele fica mal educado e diz:

No WebApplicationContext found: no ContextLoaderListener registered?

X

O mais estranho é que no log o autowire funciona:

DefaultListableBeanFactory [DEBUG] Creating instance of bean 'userAuth'
CachedIntrospectionResults [DEBUG] Getting BeanInfo for class [com.app.user.UserAuth]
CachedIntrospectionResults [DEBUG] Caching PropertyDescriptors for class [com.app.user.UserAuth]
CachedIntrospectionResults [DEBUG] Found bean property 'class' of type [java.lang.Class]
CachedIntrospectionResults [DEBUG] Found bean property 'users' of type [com.app.user.Users]
InjectionMetadata [DEBUG] Found injected element on class [com.app.UserAuth]: AutowiredMethodElement for public void com.app.user.UserAuth.setUsers(com.app.Users)
DefaultListableBeanFactory [DEBUG] Eagerly caching bean 'userAuth' to allow for resolving potential circular references
InjectionMetadata [DEBUG] Processing injected method of bean 'userAuth': AutowiredMethodElement for public void com.app.user.UserAuth.setUsers(com.app.user.Users)

Mas quando vou rodar a autenticação a dependência “User” está nula…

Lucas_Cavalcanti

qual versão do VRaptor vc usa? na 3.3.1 deveria funcionar tranquilo com o listener e o application na web-inf

X

Estou com a última versão disponível no maven, justamente a 3.3.1…

X

Então… depois de dar uma debugada aqui estou com algumas dúvidas…

Não devo declarar o ContextLoaderListener do Spring dentro do web.xml, certo? Isto porque o Vraptor vai criar o contexto e herdar as configurações do spring no applicationContext.xml. O problema disto é que ao utilizar o filtro do Spring Security, ele reclama que não há um WebApplicationContext. Mas o Vraptor já não criou este cara? Ao criar, o filter do spring não deveria estar dentro do contexto?

O porque da pergunta. Quando declaro o ContextLoaderListener no web.xml são criados 2 contextos. Pra checar isto, simplesmente loguei o construtor default de um bean meu com @ApplicationScoped. O detalhe é que este mesmo bean está declarado no applicationContext.xml porque preciso definí-lo no sec:authentication-provider/ da configuração do spring security. Ao subir a app, este bean é criado 2x. Uma vez pelo contexto spring (sem injeção) e outra pelo contexto VRaptor (com a injeção blz). É aí que vem o problema… Quando o filter do spring é executado ele pega justamente a instância que está no contexto do spring, e não do Vraptor que, consequentemente, não resolveu a injeção…

Em suma: Estou viajando ou o Vraptor deveria criar/herdar o contexto spring e utilizar um container só na execução?

Lucas_Cavalcanti

Se vc declarou o bean no applicationContext.xml, tire as anotações do VRaptor, senão ele vai criar duas vezes mesmo

X

Dá na mesma, pois o spring vai usar o cara que está no contexto do spring, onde a injeção não foi resolvida…

Lucas_Cavalcanti

declara a dependência como @Autowired(optional=true).

O VRaptor vai recriar a dependência, passando os componentes dele…

a classe vai ser inicializada duas vezes, mas a dependência vai funcionar e o VRaptor vai usar uma só.

X

Lucas,

Não encontrei a opção @Autowired(optional=true). Temos somente a @Autowired(required=true/false). É isto mesmo? De qualquer forma, o erro persiste e exatamente com o mesmo comportamento…

Detalhe importante: Estou usando Servlet 3.0. Será alguma incompatibilidade? Pergunto porque se o VRaptor já criou o WebApplicationContext, o filter do spring security deveria enxergá-lo, e não pedir para adicionar o ContextListener no web.xml…

Lucas_Cavalcanti

o VRaptor não cria outro webappContext se já existe um… habilita o log de debug do VRaptor, e posta aqui o que aparece na inicialização do sistema, plz

X

Segue…

valeu pelo esforço Lucas!

X

O primeiro log que mandei não tem o ContextListener do spring no web.xml.

Este log que estou enviando agora tem o ContextListener (Se não tiver, o filter do spring security reclama)… Neste log dá pra ver a criação do context 2x, uma pelo spring, outra pelo Vraptor…

Meu web.xml está assim:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">
      
  <display-name>App</display-name>
  
	<context-param>
		<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
		<param-value>messages</param-value>
	</context-param>

  	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>WEB-INF/web-context.xml</param-value>
	</context-param>
	
 	
  	<filter>
		<filter-name>vraptor</filter-name>
		<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>vraptor</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>
	
  	<listener>
  		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 	</listener>
 	
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>


	
</web-app>

O contextConfigLocation ali do web.xml é uma gambi que eu fiz pra que o applicationContext.xml fique no classpath. Este web-context.xml tem somente um import pro xml do classpath. Caso não use o ContextListener, este cara é ignorado…

saoj

Por isso que eu sou a favor de frameworks full-stack. Usar Spring para fazer IoC é trazer uma complexidade extra. Sempre que possível prefiro fugir de Spring, e se o framework oferece IoC nativamente é muito melhor.

PS: Spring não é uma unanimidade. Pergunte ao Google porque eles fizeram o Guice.

X

@saoj
Concordo… Porém, estou utilizando o Spring por causa de wrappers de integração que vou utilizar… Mas este é assunto pra um outro post :smiley:

De volta ao problema… Lucas, Quando o VRaptor cria o RequestContextListener ele não o registra no ServletContext, como acontece com o ContextLoader do Spring, certo? Caso isto seja feito pelo VRaptor, este problema não seria resolvido não? Vc sabe de kbça se há algum efeito colateral nisto, além de um IllegalStateException caso o ContextLoaderListener for utilizado?

saoj

xenevreu:
@saoj
Concordo… Porém, estou utilizando o Spring por causa de wrappers de integração que vou utilizar… Mas este é assunto pra um outro post :smiley:

Por curiosidade e dúvida mesmo, o que seriam esses wrappers de integração? Pode dar um exemplo?

X

Alguns facilitadores como JmsTemplate, spring data e outros, por exemplo… Agora vc até me deixou em dúvida se wrapper seria um termo correto! kkk

Lucas_Cavalcanti

xenevreu, dá pro vraptor registrar no ServletContext sim… vc sabe como ele faz isso?

pode abrir uma issue lá, por favor, pra gente fazer isso antes da próxima versão?

se estiver a fim de implementar e mandar um pull request :wink:


abraço

Lucas_Cavalcanti

o VRaptor é full-stack :wink: só que ao invés de reimplementar todas as coisas ele usa o já está pronto e consolidado a vários anos :wink:

saoj

From Wikipedia:

Uma coisa é GLUE framework outra é FULL STACK framework: http://www.tonylea.com/2011/glue-framework-vs-full-stack-framework/

Você até pode usar um container por baixo, desde que o framework abstraia e forneca uma API consistente e integrada que efetivamente proteja o desenvolvedor da complexidade extra de um framework externo. Se não temos a famosa SALADA de FRAMEWORKS, com o qual Java é bem famoso.

Um framework full stack oferece solucões para o PROBLEMA INTEIRO de forma independente, não através da integracão (glue) com N outros frameworks. Ele é uma camada acima, coesa e completa, com API própria. O controlador MVC é o menor problema de um framework web.

X

Opa Lucas!

Segue a issue: https://github.com/caelum/vraptor/issues/386

Acho q sei o funcionamento do registro sim… Vou tentar fazer por aqui e te aviso…

valeu novamente pelo esforço aí!

X

De volta… Desculpa a demora ae, é que só tive tempo de voltar nisto hj! :smiley:

Seguinte, fiz a alteração aqui localmente e funcionou… Só não sei se coloquei no lugar certo! rs

Dentro da classe SpringBasedContainer, o método start ficou:

public void start(ServletContext context) {
        parentContext.setServletContext(context);
        parentContext.addBeanFactoryPostProcessor(new BeanRegistrationProcessor(this));
        parentContext.refresh();
        parentContext.start();
        context.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, parentContext);
    }

Pelos meus testes (a minha necessidade) funcionou na boa… É isto mesmo, ou seria melhor isto ficar dentro do SpringProvider?

Só pra registrar… Outro detalhe importantíssimo pra quem está usando Spring Security + Vraptor é a ordem de declaração dos filters. O do Spring Security deve vir antes do VRaptor, caso contrário alguns problemas aparecem… No meu caso, não conseguia de jeito nenhum usar o SecurityContextHolder.getContext().getAuthentication() rs… Depois q me liguei no debug que o VRaptor estava rodando antes do Spring, e é claro que o authentication ia estar nulo! :smiley: … Acho que já vi algo falando sobre isto em outro post, mas nunca é tarde pra reforcar…

Abraço!

Criado 17 de maio de 2011
Ultima resposta 10 de set. de 2011
Respostas 29
Participantes 4