VRaptor + Injeção no Field

Achei alguns posts aqui no GUJ e na lista de discussão do VRaptor.

http://groups.google.com/group/caelum-vraptor/browse_thread/thread/630a64caccf465ea
http://www.guj.com.br/java/228622-vraptor-setar-valores-no-controller
http://www.guj.com.br/java/218207-ioc-vraptor

Mas, não funcionou aqui. Não sei se fiz algo de errado. Tenho o @Component anotado.

[code]private ClienteDao clientes;

@Autowired
public void setClientes(ClienteDao clientes)
{
this.clientes = clientes;
}[/code]

Preciso fazer alguma outra configuração? Ou o @Component anotado já basta?

P.S: Não posso fazer a injeção no construtor. Porque essas classes serão serviços do BlazeDS (comunicação com um cliente em Flex) e o BlazeDS exige que a classe tenha ao menos um construtor nulo. Ou seja, a injeção por construtor não funcionaria.

a injeção só vai funcionar se foi o VRaptor quem instanciou a classe, se foi o BlaseDS não rola

E tem alguma outra maneira (qualquer maneira) de injetar um @Component? Sem ser pelo construtor, nesse caso?
Ou nesse caso não posso usar o VRaptor?

é o blaseDS que dá new nessa classe?

Vou verificar…

Lucas,

Ainda não consegui montar o workspace para debugar o BlazeDS para verificar, com certeza, se é ele quem cria a classe.
Mas, eu acredito que seja ele.

Para adiantar:

-Se BlazeDS não é quem cria a classe = VRaptor deveria injetar corretamente
-Se BlazeDS é quem cria a classe = VRaptor não conseguirá injetar

Certo?

Então, pergunto: Se o VRaptor não conseguirá injetar. Tenho como fazer essa injeção do @Component “manualmente” (sem depender do VRaptor). Usando um dos providers como Spring, Guice ou Pico?

tenta fazer com que o flex mande uma request pra sua aplicação VRaptor. Senão o único jeito é fazendo um static lookup (que é feio pra cacete).

Então… o que você quer dizer em fazer um request para a aplicação VRaptor?

Mais informações:

O projeto Java estava rodando com VRaptor e estava disponibilizando os serviços por HTTP (@Resource). Então, se eu chamar no Flex os dados por HTTP irá fazer o request diretamente no VRaptor. E funcionará tanto a injeção por construção, como também acho que funcionará no setter.

No entanto, a forma mais usada e rápida de comunicação no Flex é por RemoteObject. E quem faz a comunicação entre o cliente e o servidor é o BlazeDS. Então, no servidor estou com o VRaptor, onde tem serviços sendo disponibilizados como HTTP. Mas, gostaria de disponibilizar o acesso a alguns dados por RemoteObject.

Ele tem um arquivo de configuração xml onde atribuo uma id para cada serviço disponibilizado e informo o package onde está o serviço. Depois, no Flex eu só passo a localização do servidor e o nome do serviço que será chamado. O Flex não tem nenhuma ligação com o servidor Java. Tudo passa pelo BlazeDS.

Portanto, creio, que o BlazeDS receba essa mensagem com o id do serviço que ele precisa chamar. E ela fica responsável por criar a classe. (senão não teria necessidade de informar o package…)

Não entendi ainda, por que o BlazeDS como responsável por criar a classe, a injeção das dependencias não funciona? Com nenhum framework ela funcionaria?

a injeção não funciona pq quando o BlaseDS instancia a classe, ela não é gerenciada pelo VRaptor.

vc consegue pegar a instancia dessa classe de outro lugar? ou ela executa alguma coisa sem nem passar pelo vraptor?

Ta aqui o stacktrace de uma Exception: (me ajudou a entender melhor o ciclo da requisição)

O request está passando pelo VRaptor!
O BlazeDS tem uma servlet que fica, normalmente, em: http://servidor/nomedoprojeto/messagebroker/amf

Essa servlet é uma fachada para todos os acessos, ou seja, TODA requisição realizada pelo cliente Flex (através do AMF) o servidor Java recebe através dessa servlet. Portanto, passa pelo VRaptor.

A requisição também passa pelo provider:
at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)

No entanto, nesse momento que a classe passa pelo provider é apenas uma mensagem que contém a localização do serviço, parametros, e outras informações da requisição. (Não existe a classe criada!)

Depois, por dentro do BlazeDS é criada a classe que executa a lógica e retorna o resultado em outra mensagem.

Vou verificar se essa classe responsável por criar o serviço não tem uma interface que eu possa implementar para alterar o comportamento da criação. Se eu conseguisse, teria uma maneira do VRaptor injetar daí?

Stacktrace:

[quote]15:42:35,133 DEBUG [VRaptor ] VRaptor received a new request
15:42:35,145 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ResourceLookupInterceptor
15:42:35,146 DEBUG [DefaultResourceTranslator] trying to access /messagebroker/amf
15:42:35,148 DEBUG [VRaptor ] VRaptor ended the request
15:42:35,195 DEBUG [VRaptor ] VRaptor received a new request
15:42:35,204 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ResourceLookupInterceptor
15:42:35,205 DEBUG [DefaultResourceTranslator] trying to access /messagebroker/amf
[BlazeDS]Unable to create a new instance of type ‘br.com.cauirs.tipos.Quantidade’.
flex.messaging.MessageException: Unable to create a new instance of type ‘br.com.cauirs.tipos.Quantidade’. Types cannot be instantiated without a public, no arguments constructor.
at flex.messaging.util.ClassUtil.createDefaultInstance(ClassUtil.java:161)
at flex.messaging.io.amf.AbstractAmfInput.createObjectInstance(AbstractAmfInput.java:179)
at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:409)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:152)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:130)
at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:437)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:152)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:130)
at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:437)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:152)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:130)
at flex.messaging.io.amf.Amf3Input.readArray(Amf3Input.java:358)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:156)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:130)
at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:437)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:152)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:130)
at flex.messaging.io.amf.Amf0Input.readObjectValue(Amf0Input.java:123)
at flex.messaging.io.amf.Amf0Input.readArrayValue(Amf0Input.java:359)
at flex.messaging.io.amf.Amf0Input.readObjectValue(Amf0Input.java:127)
at flex.messaging.io.amf.Amf0Input.readObject(Amf0Input.java:94)
at flex.messaging.io.amf.AmfMessageDeserializer.readObject(AmfMessageDeserializer.java:227)
at flex.messaging.io.amf.AmfMessageDeserializer.readBody(AmfMessageDeserializer.java:206)
at flex.messaging.io.amf.AmfMessageDeserializer.readMessage(AmfMessageDeserializer.java:126)
at flex.messaging.endpoints.amf.SerializationFilter.invoke(SerializationFilter.java:145)
at flex.messaging.endpoints.BaseHTTPEndpoint.service(BaseHTTPEndpoint.java:291)
at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:353)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at br.com.caelum.vraptor.resource.DefaultResourceNotFoundHandler.couldntFind(DefaultResourceNotFoundHandler.java:41)
at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:71)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
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:857)
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)[/quote]

Confirmado. Tenho como modificar o modo que o BlazeDS cria o objeto.

Ao passar pelo servlet é um objeto do tipo RemotingMessage com as informações da requisição. Ai utiliza um Adapter para fazer a criação do objeto. Por padrão, é usado o JavaAdapter. Mas, posso criar qualquer um…

Então, é o BlazeDS mesmo quem cria o objeto. Porém, utilizando um Adapter personalizado a classe estará no meu projeto posso dizer o que fazer com o objeto criado.

Tenho como “ativar” essa injeção de dependências após a criação do objeto?

tem como mudar o modo que o BlaseDS instancia as classes de serviço, então dá pra fazer o VRaptor cuidar disso.

O David Paniz e o Erich Egert aqui da Caelum estão trabalhando nessa integração, assim que estiver estável eu te dou um toque.

Abraços

Opa… valeu

Acabamos disponibilizar o plugin para fazer a chamada do seu controller pelo BlazeDS.
Você pode baixar o jar (vraptor-flex.jar) na área de downloads do VRaptor no github: https://github.com/caelum/vraptor/

Na página do projeto (https://github.com/caelum/vraptor/tree/master/vraptor-plugin-flex) tem uma breve explicação sobre a configuração do plugin, mas já aproveitando a resposta, para a chamada funcionar você precisa registrar a factory do VRaptor no seu service-config.xml

<factories>
  <factory id="vraptor" class="br.com.caelum.vraptor.flex.VRaptorServiceFactory" />
</factories>

e na hora de registrar seus destinations, você tem que passar o nome canonico do seu controller e a fabrica do vraptor:

<destination id="myVRaptorController">
  <properties>
    <factory>vraptor</factory>
    <source>br.com.caelum.vraptor.example.MyController</source>
  </properties>
</destination>

Nesta versão já estamos suportando interceptors, mas como nem todo interceptor faz sentido tanto para o flex quanto para o html comum, criamos uma nova anotação @FlexIntercepts que deve anotar um classe que implementa a mesma interface Interceptor. (Uma classe que implementa Interceptor PODE usar a @Intercepts e @FlexIntercepts ao mesmo tempo sem problemas)

David parabéns ficou muito bom :smiley:
Agora é possível até injeção de dependências pelo construtor. Ficou melhor do que eu estava esperando!

Só uma observação: usando o jar que está no github está dando um erro de NullPointerException, precisei copiar as classes para dentro do meu projeto.

nullpointer aonde?

Acredito ter seguido corretamente as instruções porém durante o deploy recebo isso:

Mudei a factory de:

<factories> <factory id="vraptor" class="br.com.caelum.vraptor.flex.VRaptorServiceFactory" /> </factories>

para:

<factories> <factory id="vraptor" class="br.com.caelum.vraptor.flex.blazeds.VRaptorServiceFactory" /> </factories>

e parece que mudou o erro para:


exception

javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/apache/commons/httpclient/UsernamePasswordCredentials
	flex.messaging.MessageBrokerServlet.init(MessageBrokerServlet.java:184)
	org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261)
	org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88)
	org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
	org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)
	org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
	org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654)
	org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951)
	java.lang.Thread.run(Unknown Source)

root cause

java.lang.NoClassDefFoundError: org/apache/commons/httpclient/UsernamePasswordCredentials
	java.lang.Class.forName0(Native Method)
	java.lang.Class.forName(Unknown Source)
	flex.messaging.util.ClassUtil.createClass(ClassUtil.java:65)
	flex.messaging.Destination.createAdapter(Destination.java:358)
	flex.messaging.config.MessagingConfiguration.createAdapter(MessagingConfiguration.java:431)
	flex.messaging.config.MessagingConfiguration.createDestination(MessagingConfiguration.java:423)
	flex.messaging.config.MessagingConfiguration.createServices(MessagingConfiguration.java:391)
	flex.messaging.config.MessagingConfiguration.configureBroker(MessagingConfiguration.java:117)
	flex.messaging.MessageBrokerServlet.init(MessageBrokerServlet.java:132)
	org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261)
	org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88)
	org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
	org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)
	org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
	org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654)
	org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951)
	java.lang.Thread.run(Unknown Source)

root cause

java.lang.ClassNotFoundException: org.apache.commons.httpclient.UsernamePasswordCredentials from BaseClassLoader@7428a612{vfs:///D:/programas/jboss-6.0.0.Final/server/default/deploy/AgileSuitePasmania.war}
	org.jboss.classloader.spi.base.BaseClassLoader.loadClass(BaseClassLoader.java:480)
	java.lang.ClassLoader.loadClass(Unknown Source)
	java.lang.Class.forName0(Native Method)
	java.lang.Class.forName(Unknown Source)
	flex.messaging.util.ClassUtil.createClass(ClassUtil.java:65)
	flex.messaging.Destination.createAdapter(Destination.java:358)
	flex.messaging.config.MessagingConfiguration.createAdapter(MessagingConfiguration.java:431)
	flex.messaging.config.MessagingConfiguration.createDestination(MessagingConfiguration.java:423)
	flex.messaging.config.MessagingConfiguration.createServices(MessagingConfiguration.java:391)
	flex.messaging.config.MessagingConfiguration.configureBroker(MessagingConfiguration.java:117)
	flex.messaging.MessageBrokerServlet.init(MessageBrokerServlet.java:132)
	org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285)
	org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261)
	org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88)
	org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
	org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)
	org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
	org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654)
	org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951)
	java.lang.Thread.run(Unknown Source)

class not found… tá faltando o jar do commons-httpclient

já fiz isso e dai ta dando: