[VRaptor 3] Acesso ao BeanFactory do Spring

Oá,

Alguém sabe se é possível de dentro de um Controller ter acesso ao BeanFactory do Spring?
Preciso fazer um factory.getBean(Classe.class)… E não posso injetar pelo construtor ou anotação pq é em tempo de execução que vou saber qual o bean que preciso.

Obrigado

olá,

O VRaptor tem uma interface para isso: a Container, que vc pode receber no construtor e chamar assim:

container.instanceFor(Classe.class);

De qualquer forma é meio estranho precisar desse tipo de coisa num controller, geralmente indica um problema de design da sua classe. Se você explicar o que está tentando fazer talvez a gente possa chegar numa solução melhor.

Abraços

Oi Lucas,

Obrigado pela resposta.

De fato é meio estranho isso que eu preciso…
E eu ja to testando outra forma para não precisar recuperar o bean desta forma.

Acontece que to arquitetando meu sistema para permitir qualquer programador desenvolva módulos pra ele… e o admin instale/remove estes módulos com o sistema em execução

Estes módulos são telas Velocity seguindo um protocolo bem simples.
Mas as vezes este módulo precisa acessar componentes internos do sistema (ex: o cadastro de usuarios). E também pode conter componentes que serão disponibilizados por outros módulos.

Só que pra ter um controle sobre os componentes do sistema o programador ao empacotar o módulo precisa incluir um XML descritor mencionando quais os componentes de sistema que o módulo precisa.
Assim, quando o sistema for executar o módulo, ele dará acesso apenas às interfaces dos componentes que estão no descritor do módulo.

Ou seja, o meu vraptor controller que carrega e dispacha o request para um novo módulo, só vai saber quais as dependências necessárias apenas quando o usuário acessar o tal módulo.

E o descritor que menciona os componentes ta sendo necessário para:

  • na instalação do módulo, o admin saber que tipo de informação o módulo vai poder acessar;
  • para o sistema saber quais componentes do sistema (aqui vou usar a BeanFactory) vai carregar quando for fazer o dispach para a página Velocity do módulo;
  • e para “nomear” o componente para ser acessado pelo Velocity.

O módulo nunca vai ter acesso as implemetações dos componetes, ele sabe qual interface precisa, que o sistema faz um “getBean()” pra ele se o módulo tiver permissão naquele componente (Bean do Spring)

obs: componente == bean registrado no spring

to viajando muito? heheheh

valeu!

um problema com essa abordagem é que a pessoa precisa executar lógicas de negócio dentro dos templates Velocity.

Isso é uma má pratica, vc deveria executar apenas lógica de apresentação dentro do Velocity.

com o VRaptor vc pode fazer esses módulos serem jars que contém controllers (que conseguem receber as suas dependências no construtor) e as páginas em velocity (ou jsp) para serem colocadas na /WEB-INF/vm (ou /WEB-INF/jsp).

Tem um jeito no VRaptor pra ler esses jars automaticamente e registrar tudo que tem neles.
ou vc cria um context-param no web.xml chamado
br.com.caelum.vraptor.packages com o valor do pacote base do módulo, ou vc cria um um arquivo dentro do /META-INF do jar chamado br.com.caelum.vraptor.packages com o pacote base do módulo.

Olá! Boa noite!
Po, cara… fiquei meio grilado agora.
eu também fiz algo parecido numa funcionalidade hoje, mas, já que vc falou que isso é estranho num controller, gostaria de saber sua opinião.
não sei se fui eu que entendi errado e essa situação é diferente da minha.
mas no meu caso, eu tenho 3 links de relatório que mandam para um mesmo controller.
esses links chamam o mesmo método pq o que eles fazem são a mesma coisa, mas de maneiras diferentes.
então ao invés de eu enfiar ifs dentro do dito cujo, eu criei classes Actions para cada um desses links,
implementei uma interface para todos e no controller, eu faço um class forname e dou um execute.
então fica mais ou menos assim

os links:
endereco/Action1
endereco/Action2
endereco/Action3

levando em conta que as 3 implementam uma interface x, eu faço no controle mais ou menos isso:

X x = (X)Class.forName(parametro).getInstance(); x.execute();

Essa não seria a melhor saída pra evitar os ifs, no meu caso?

Aproveitando o tópico, já que tenho a mesmíssima dúvida, sabe me dizer se eu posso fazer algo parecido no spring pra usar a bean factory?
pq eu estou na mesma situação que o nosso amigo.
Como eu dou um getInstance(), eu não consigo injetar uma dependência nessas Actions.

Muito obrigado!

se é uma interface vc pode tentar fazer algo assim:

public void metodoDoController(Action action) {
   action.execute();
}

passar na requisiçao um parametro
action=ClasseDaAction

e criar um converter pra ela:

@Convert(Action.class)
public class ActionConverter implements Converter<Action> {

    public ActionConverter(List<Action> actions) {
         this.actions = actions;
    }
    public Action convert(String value, ....) {
         //retorna a action da classe do value, que é o parametro que vai vir da requisiçao
    }

}

algo assim deve funcionar do jeito que vc quer

Cara, parece muito ninja.
Amanha vou colar e tentar entender melhor.
Se nao der certo, eu mando os trechos de codigo, pode ser?

Mas me diz, cara. No caso q eu usei fica estranho tambem?
É bom saber… hehehe

é razoavelmente estranho sim vc trocar a action com um parâmetro…

eu faria um método pra cada Action, mudando pela url ou algo do tipo…

Então, cara…
Não consegui aplicar não.
Talvez eu não tenha deixado claro, mas estou usando o Spring MVC.
Estou falando isso pq pediu pra adicionar dependência pra @Convert, então imaginei que fosse do VRaptor, já que o tópico é para ele. lol
Só aproveitei o tópico pq achei interessante vc falar que fica estranho uma parada que eu tinha feito e tinha achado linda! hahaha
De qq forma, é a mesma situação, com frameworks diferentes. não cometi nenhum pecado, né?

Então…
Deixa eu repetir o post anterior, mas colando uns trechos.
no jsp, eu tenho 3 links
href=“blablabla/NomeAction1”
href=“blablabla/NomeAction2”
href=“blablabla/NomeAction3”

todas essas Actions implementam uma classe abstrata InterfaceAction

[code]@Component
public abstract class RelatorioActionInterface {

@Inject
protected PeriodoUtil pu;
public abstract void execute(Map<String, Object> model);

}[/code]

coloquei abstrata pq todas terão que ter esse objeto que quero injetar (e é esse que não estou conseguindo injetar!)

no controller, eu tenho um método assim:

    [code]@RequestMapping("blablabla/{actionName}")
public String definePeriodo(@PathVariable String actionName, Map<String, Object> model) {
    model.put("actionName", actionName);
    try {
        InterfaceAction rel = (InterfaceAction) Class.forName("fqn."+actionName).newInstance();
        rel.execute(model);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "blablablabla/view";
}[/code]

Não sei se ficou muito claro.

Abraços.

isso que dá reaproveitar tópicos :wink:

faça o seguinte: Receba a beanFactory no controller,

faça o class.forName e guarde o Class<> que ele retorna

e chame beanFactory.getBean(classe); pra pegar a instancia com injeção de dependencias…

cada action precisa ser um component e pode ter uma interface em comum, ao invés de uma classe abstrata…

dica: se vc fizer o class:

Class<? extends InterfaceAction> classe = Class.forName(....);

o getBean vai retornar uma InterfaceAction já

Rapaz,
ficou assim:

Controller

@RequestMapping("blablabla/{actionName}") public String definePeriodo(@PathVariable String actionName, Map<String, Object> model) throws Exception { model.put("actionName", actionName); beanFactory.getAction(actionName).execute(model); return "blablablabla/view"; }

Factory

[code]public class ActionFactory {

@Inject
private ApplicationContext applicationContext;

public ActionInterface getAction(String action){
	return (ActionInterface ) applicationContext.getBean(action+"extensao");
}

}
[/code]

Na tua opinião, ficou melhor?

Grande abraço e obrigado por tudo.

ficou legal =) melhor que class forname :wink:

uhul! valeu pelas dicas \o/