Invocar diretamente conversão de tipos no VRaptor

Pessoal, boa noite. Eu estou precisando invocar diretamente a api de conversão do VRaptor.

Meu objetivo é o seguinte: preciso criar um controler genérico que salva entidades de qualquer tipo. Logo, esse controler deve receber os dados do formulário, decidir qual classe de entidade deve ser instanciada e em seguida popular a instância recém criada com os dados vindos do formulário, para então salvar.

Como o controller só vai saber a classe depois que os dados chegarem, não posso fazer algo como isso:

public void add(Pessoa pessoa) { … }

No final, o controller deve se parecer com isso:

public void add(Map<String, String> params) { … }

e a partir dos dados contidos em params é que será continuado todo o processo.

Alguém tem uma pista?

essa sua classe que tem o método add vai sempre redirecionar pra outro lugar que vai tratar a requisição de verdade, ou tudo vai ser genérico e estar nesse método?

qual é o motivo de vc fazer isso tão genérico?

Como eu tinha falado, o que eu quero é simples: quero receber os dados do formulário que chegam no controller, descobrir que classe instanciar, instanciar a classe adequada e preencher com as informações que chegaram do formulário.

O VRaptor faz isso, mas a classe que será instanciada fica definida dentro do controler, na assinatura do método e eu quero que isso seja dinâmico.

O motivo de eu estar procurando essa funcionalidade é que eu estou desenvolvendo um framework que gera um crud automático, entre outras coisas. Construção da interface automaticamente e um único controler para fazer o crud de todas as entidades, e não um controler separado para cada entidade.

não acho que isso seja uma boa idéia, em geral, pois cada entidade tem uma validação diferente, tanto de modelo qto de negócio.

o componente que faz isso é o ParametersProvider.

o que vc pode fazer é sobrescrevê-lo e fazer a lógica específica desse seu controller genérico nele…

assim vc pode receber um Object nas lógicas, e esse object vai conter a entidade populada…

o código pra fazer isso talvez seja um pouco complicado, pois vc tem que ou enganar o VRaptor passando um ResourceMethod falso, ou vc vai ter que copiar o código da implementação default do vraptor e modificar o que vc precisa…

na segunda opção (que é mais simples), copie essa classe para o seu projeto (o conteúdo dela!)

talvez vc tenha que copiar algumas outras classes também

modifique o método getParametersFor, passando os names, types e classes apropriados, e o resto do código vai fazer a mágica

Nossa! Valeu mesmo pela resposta.

Vou juntar as informações que você me passou com o que eu to descobrindo aqui debugando o vraptor.

Valeu mesmo!

só cuidado que essa classe que eu te passei está na última versão do repositório. A classe foi refatorada, então ela está um pouco (eu diria bastante) diferente da última versão lançada (3.3.1)

Depois de debugar e ler código fonte, agora eu pergunto:

Tem como configurar quais interceptors serão executados para um dado controller?

Eu quero criar um controller bem especial e mudar o interceptor que instancia os parâmetros para este controller. Quero trocar o interceptor padrão do Vraptor por um outro “batizado”.

vc quer substituir totalmente como o VRaptor cria os parâmetros para esse controller específico?

é mais fácil sobrescrever o componente que cria os parâmetros:

crie a classe:

@Component
public class CustomParametersProvider implements ParametersProvider {
     public CustomParametersProvider(ParametersProvider delegate, ...) {
           this.delegate = delegate;
           //...
     }
     @Override
     public Object[] getParametersFor(ResourceMethod method, ...) {
          if (ehOControllerEspecial(method) {
              return suaLogicaDeCriarOsParametros();
          } else {
              return delegate.getParametersFor(...);
          }
     }
}

Boa idéia essa de sobreescrever o componente.

Mas este provider customizado só deve ser invocado junto com um determinado controller, para os outros controllers eu quero que tudo seja original do VRaptor.

Como se faz para este provider customizado ser chamado apenas para um determinado controller?

if (method.getResource().getType().equals(MeuController.class) {...}

Hum, isso me cheira a strategy para ajustar tudo isso. Agora acho que já dá pra continuar decidindo umas coisas.

No trabalho que eu estou fazendo, imagino uns 3 controllers “especializados”: um para crud, outro para interagir com uma engine de bpm (processos) e um para relatórios.

Obrigado mais uma vez pela atenção!