VRaptor 3 + Spring

29 respostas
galmeida

Olá,
Estou estudando a troca do atual framework web de uma de nossas aplicações para o vraptor3, essa aplicação já faz uso do spring.
Se o VR for configurado para usar spring é possivel passar meu atual ApplicationContext como parent para o ApplicationContext que o vr cria?

Obrigado,
galmeida

29 Respostas

Lucas_Cavalcanti

olá galmeida

isso não tá implementado ainda, mas vai entrar num próximo release (beta-3 ou rc-1)

[]'s

galmeida

Mais uma vez obrigado, pela prontidão nas respostas

Lucas_Cavalcanti

Acabamos de lançar o beta 3 do vraptor, que usa seu applicationContext.xml como base do spring, se ele estiver no classpath.

[]'s

wariows

lucascs:
Acabamos de lançar o beta 3 do vraptor, que usa seu applicationContext.xml como base do spring, se ele estiver no classpath.

[]'s

Oi lucas, já pensaram em usar o esquema de configuração do spring via annotation?

@Configuration, @Bean, etc?

Talvez vocês pudessem ter hot spot pra que o cara possa utilizar tanto o estilo de configuração por annotation, quanto o applicationContext.xml…

btw, esses repositórios git me confundem… baixei o git do vraptor aqui no eclipse, mas não consigo sincronizar direito :roll:

Paulo_Silveira

oi wariows

creio que da maneira que foi implementada as anotacoes tambem serao escaneadas (lucas, confirma?)

e porque o git nao esta sincronizando? sabe o erro que da?

abracos!

wariows

Paulo Silveira:
oi wariows

creio que da maneira que foi implementada as anotacoes tambem serao escaneadas (lucas, confirma?)

e porque o git nao esta sincronizando? sabe o erro que da?

abracos!

Vi pelo browser do github que o lucas tinha feito atualizacoes (as do spring com o applicationContext.xml), quando dei o ‘fetch from’ apareceu as atualizacoes, ele as fez, mas os arquivos não mudaram… não sei pq… talvez tenta feito algo errado… baixei novamente o git, vo esperar uma proxima atualizacao pra ver se consigo sincronizar…

Vou testar aqui com o @Configuration, se funcionar aviso.

wariows

wariows:
Paulo Silveira:
oi wariows

creio que da maneira que foi implementada as anotacoes tambem serao escaneadas (lucas, confirma?)

e porque o git nao esta sincronizando? sabe o erro que da?

abracos!

Vi pelo browser do github que o lucas tinha feito atualizacoes (as do spring com o applicationContext.xml), quando dei o ‘fetch from’ apareceu as atualizacoes, ele as fez, mas os arquivos não mudaram… não sei pq… talvez tenta feito algo errado… baixei novamente o git, vo esperar uma proxima atualizacao pra ver se consigo sincronizar…

Vou testar aqui com o @Configuration, se funcionar aviso.

Não funcionou, de acordo com a documentação do spring qualquer um dos jeitos abaixo funcionaria para configurar via java:

Pelo que vi no código do vraptor, está utilzando o ClassPathXmlApplicationContext, talvez fosse o caso de utilizar AnnotationApplicationContext como parent do ClassPathXmlApplicationContext ou vice-versa.

Vou tentar fazer isso aqui e dou um feedback

[]´s

Lucas_Cavalcanti

olá wariows

dá uma olhada no vraptor-spring-example, que ele tem um applicationContext.xml que tem a configuração pra que
o spring funcione com as anotações que você falou…

e sim, por enquanto eu to pegando um ClassPathXmlApplicationContext com o applicationContext.xml… Vou tentar
abstrair a criação do ApplicationContext do spring para o próximo release do vraptor… vai ser algo do tipo implementar
uma interface determinada pra dizer qual ApplicationContext você quer…

por enquanto, tente usar o applicationContext.xml básico que está no vraptor-spring-example

[]'s

Lucas_Cavalcanti

e outra coisa: o plugin de git pra eclipse não funciona muito bem… tente usar o git linha de comando que é melhor…
em github.com/guides tem os passos básicos pra usar git

galmeida

lucascs:
Acabamos de lançar o beta 3 do vraptor, que usa seu applicationContext.xml como base do spring, se ele estiver no classpath.

[]'s

Ótima notícia, vou poder tirar minha “implementação caseira” :slight_smile:

galmeida

@lucascs
Lucas, peguei o commit que vc fez p/ carregar o applicationContext.xml, apesar de funcionar como esperado, ele não atendeu minha necessidade, vou explicar porque:

meu cenário é o seguinte, temos um projeto em desenvolvimento onde usávamos um outro framework web e o spring. Nesse momento estamos substituindo o framework antigo pelo vraptor, mas essa substituição tem que ser gradual p/ não causar muito impacto no cronograma.

Nesse projeto o spring sobe através do org.springframework.web.context.ContextLoaderListener, e portanto quando o VRaptorApplicationContext é inicializado, ele sobe uma segunda instância do container.

Se vocês julgarem apropriada a inclusão no vraptor, uma possível solução seria o VRaptorApplicationContext fazer algo assim:

public VRaptorApplicationContext(SpringBasedContainer container, ServletContext servletContext, String... basePackages) {
    this.container = container;
    this.basePackages = basePackages;
    WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);

    if (webApplicationContext != null) {
        setParent(webApplicationContext);
    } else if (VRaptorApplicationContext.class.getResource("/applicationContext.xml") != null) {
        setParent(new ClassPathXmlApplicationContext("classpath:applicationContext.xml"));
    }
}

por hora estou usando implementações customizadas de SpringProvider e SpringBasedContainer, esse último está colocando o webApplicationContext como parent no start().

galmeida

Lucas_Cavalcanti

Ok, vou mudar isso na implementação, obrigado =)

De qualquer forma, pra próxima versão vai ter um componente responsável por procurar o ApplicationContext da sua aplicação,
daí é só implementá-lo pra pegar o que você quiser…

galmeida

legal!!

obrigado

L

O uso do applicationContext.xml próprio foi resolvido? Porque eu não consigo injetar beans criados pelo meu applicationContext.xml, os erros dizem simplesmente que meu bean não existe.

Eu até tentei rodar a aplicação vraptor-spring-example, colocando o applicationContext.xml dentro de /WEB-INF (está certo isso?). Mas mesmo assim, apareceu o mesmo erro.

Error creating bean with name ‘dogsController’: Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.caelum.vraptor.example.spring.DogsRepository br.com.caelum.vraptor.example.spring.DogsController.repository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [br.com.caelum.vraptor.example.spring.DogsRepository] is defined: Unsatisfied dependency of type [class br.com.caelum.vraptor.example.spring.DogsRepository]: expected at least 1 matching bean

Existe algo que possa resolver?

Lucas_Cavalcanti

No beta-3 ele procura um applicationContext.xml no classpath… (na WEB-INF/classes portanto ou dentro de um jar)…

na versão que tá no git ele procura ainda WebApplicationContextUtils.getWebApplicationContext(servletContext)
alem do mais você pode implementar a interface SpringLocator e dar sua própria versão do ApplicationContext

[]'s

Paulo_Silveira

Leonardo, entao, precisa colocar dentro do WEB-INF/classes mesmo…
avisa a gente se deu certo?

L

Entendi. Havendo uma configuração padrão do Spring, este será usado.

Coloquei os listeners padrão do Spring no web.xml, e funcionou beleza. Com o applicationContext.xml dentro de /WEB-INF .

<listener>
	<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Também havia colocado dentro de WEB-INF/classes, e funcionou também.

Valeu!

galmeida

lucascs:
na versão que tá no git ele procura ainda WebApplicationContextUtils.getWebApplicationContext(servletContext)
alem do mais você pode implementar a interface SpringLocator e dar sua própria versão do ApplicationContext
[]'s

Legal saber que isso foi implementado, em breve poderei mandar p/ lixo minha implementação.

[]s

wariows

Oi leonardo,

Foi resolvido sim, baixe a versão mais nova do site do vraptor. Basta colocar seu applicationContext.xml no classpath que o vraptor vai achar.

R

Lucas Cavalcanti:
olá wariows

dá uma olhada no vraptor-spring-example, que ele tem um applicationContext.xml que tem a configuração pra que
o spring funcione com as anotações que você falou…

e sim, por enquanto eu to pegando um ClassPathXmlApplicationContext com o applicationContext.xml… Vou tentar
abstrair a criação do ApplicationContext do spring para o próximo release do vraptor… vai ser algo do tipo implementar
uma interface determinada pra dizer qual ApplicationContext você quer…

por enquanto, tente usar o applicationContext.xml básico que está no vraptor-spring-example

[]'s

Lucas, aonde posso achar o vraptor-spring-example? Não achei no repositório GIT.

Lucas_Cavalcanti

não existe o spring-example pro vraptor 3…

o VRaptor já funciona com o spring automaticamente, basta colocar os jars do spring e colocar o applicationContext.xml no classpath.

R

Lucas Cavalcanti:
não existe o spring-example pro vraptor 3…

o VRaptor já funciona com o spring automaticamente, basta colocar os jars do spring e colocar o applicationContext.xml no classpath.

Ok… estava procurando mesmo um exemplo do arquivo applicationContext.xml :roll: para fazer uns testes com o VRaptor.
Valeu

Lucas_Cavalcanti

tem um exemplo num apendice da apostila do fj-28
http://www.caelum.com.br/curso/fj-28-vraptor-hibernate-ajax/

R

Valeu Lucas, melhor do que eu estava procurando. Irá me ajudar bastante.

R

Lucas,

Segui como está descrito no apêndice, porém não está achando o SessionFactory para injetar no CriadorDeSession.

O único lugar que eu declaro a criação do SessionFactory é no applicationContext.xml que está no raíz do WEB-INF. Isso é o suficiente para o VRaptor encontrar a SessionFactory correta que será injetada?

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

	<tx:annotation-driven />

	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
		
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="configLocation">
			<value>classpath:/hibernate.cfg.xml</value>
		</property>	
	</bean>
		
</beans>

Stacktrace: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

Lucas_Cavalcanti

coloque o applicationContext.xml no classpath (em alguma pasta source como src ou src/main/resources)

R

Valeu, coloquei ele no classpath agora está achando a sessionFactory.
Porém, não está funcionando a injeção da sessão.

Um exemplo bem simples:

@Component
public class BookDao 
{
	private final Session session;
	
	public BookDao(Session session)
	{
		this.session = session;
	}
	...
}
@Resource
public class BookService 
{
	private final BookDao books;
	
	public BookService(BookDao books)
	{
		this.books = books;
	}
	
	...
}
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bookDao': Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class br.com.caelum.testeGranite.dao.BookDao]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

Se eu tiro a injeção da sessão no DAO essa exceção não ocorre.

A criação da sessão é feita usando o ComponentFactory (conforme exemplo do apêndice):

@Component
public class SessionCreator implements ComponentFactory<Session>
{

	private final SessionFactory factory;
	private final Proxifier proxifier;
	private Session session;
	
	public SessionCreator(SessionFactory factory, Proxifier proxifier)
	{
		this.factory = factory;
		this.proxifier = proxifier;
	}
	
	@PostConstruct
	public void open()
	{
		this.session = proxifier.proxify(Session.class, new MethodInvocation<Session>() {
			@Override
			public Object intercept(Session proxy, Method method, Object[] args, SuperMethod superMethod) 
			{
				Session sessionDoSpring = SessionFactoryUtils.doGetSession(factory, true);
				return new Mirror().on(sessionDoSpring).invoke().method(method).withArgs(args);
			}
		});
	}

	public Session getInstance()
	{
		return this.session;
	}
	
	@PreDestroy
	public void close()
	{
		this.session.close();
	}

}

Tentei criar um ComponentFactory que só implementava o getInstance() e não tinha construtor não-nulo, mas apareceu o mesmo erro do CGLIB.

O que pode ser?

Lucas_Cavalcanti

se vc vai usar os componentes que usam AOP do spring, vc precisa que todas as classes que passam pelo aop tenham construtores sem argumentos (solução ruim) ou que todas as dependências sejam interfaces (solução boa)

no caso do bookDao, vc pode fazer:

-renomeie o BookDao para HibernateBookDao (ou algo do tipo) (Alt+Shift+R no eclipse)
-extraia a interface BookDao com os métodos pertinentes (no eclipse, Alt+Shift+T no nome da classe > Extract Interface). Lembre-se de marcar “Use supertype where possible”

blz, o CGLIB vai conseguir gerar os proxies sem problema

R

Novamente funcionou perfeitamente!

Estou te devendo algumas já rsrs
Valeu pela ajuda!

Criado 25 de agosto de 2009
Ultima resposta 20 de abr. de 2011
Respostas 29
Participantes 6