Controller dinamico - vRaptor

9 respostas
K

Talvez já existe algo nesse sentido com o vRaptor, mas não sei certo como encontrar.
Minha ideia é a seguinte,

Quero ter um Controller "dinamico"
Por exemplo, uma requisição que venha os parâmetros:

entidade=Usuario
usuario.nome=Inácio
usuario.login=inacio

Daí o mesmo controller atende também a outra requisição
entidade=Cidade
cidade.descricao=Cascavel

Daí no método desse controller, eu preciso do objeto da entidade que foi passado na requisição instanciado com os atributos que também foram passados na requisição.

9 Respostas

Rafael_Guerreiro

Por que você não pensa em um controller por funcionalidade? Assim ele trata de determinado assunto…

Se vc tiver 1 controller só para várias coisas, ele vai começar a ficar cheio de particularidades que ficariam mais limpas se fossem divididas em pequenos controllers.

K

Entendo…
Mas gostaria de centralizar operações repetitivas, como os CRUDs por exemplo. São sempre iguais. Não queria ter um Controller para cada tela de “cadastro básico” do sistema.
A maioria dos casos serão tratados por Controllers específicos, seria mais pra esses CRUDs mesmo…

Rafael_Guerreiro

Então crie um CRUD controller. Na action save, por exemplo, receba como parâmetro um Object que é o seu objeto e tente salvá-lo… Eu acredito que você vai precisar criar um conversor para conseguir salvar direito…

Lucas_Cavalcanti

dá pra vc sobrescrever um componente do VRaptor para fazer isso:

@Component
public class EntidadeParameterNameProvider extends ParanamerNameProvider {

     public EntidadeParameterNameProvider(HttpServletRequest request) {
        this.request = request;
     }

     @Override
     public String[] parameterNamesFor(AccessibleObject method) {
         String[] paramNames = super.parameterNamesFor(method);
         if (!Strings.isNullOrEmpty(request.getParameter("entidade")) {
               paramNames[0] = request.getParameter("entidade");
         }
         return paramNames;
     }
}

O vraptor usa esse componente pra decidir o nome do parametro…
daí vc deve passar na requisiçao:

entidade=usuario 
usuario.nome=Inácio 
usuario.login=inacio

deve funcionar

K

No método do Controller, eu recebo esses parametros com que nome? “entidade”?
Esse parametro é de que tipo? “Object”?

K

Esse Component tá dando uma exception ao subir o servidor:

Error creating bean with name ‘entidadeParameterNameProvider’: 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;

Tentei adicionar um @ApplicationScoped mas daí:
Error creating bean with name ‘entidadeParameterNameProvider’: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.servlet.http.HttpServletRequest]

Lucas_Cavalcanti

pode ser qqer nome no controller… o que vc tá fazendo nesse componente que eu postei acima é sobrescrevendo o nome do parametro do controller pelo parametro entidade que veio no request.

E, sim, vc deveria receber um Object, justamente pq vc não sabe qual é a classe…

o problema é que o VRaptor não vai conseguir instanciar o objeto pq ele não vai saber qual é a classe =/

nesse caso vc teria que sobrescrever o componente do VRaptor que instancia os objetos… isso talvez seja bem mais chato… quer tentar fazer?

algo que funcionaria é o velho GenericController:

public class GenericController<T> {
   //todos os métodos aqui
}

@Resource
public class UsuarioController extends GenericController<Usuario> {}

@Resource
public class ProdutoController extends GenericController<Produto> {}

e assim por diante

K

"nesse caso vc teria que sobrescrever o componente do VRaptor que instancia os objetos… isso talvez seja bem mais chato… quer tentar fazer?"
Qual é essa classe?

Eu poderia também pegar todos os atributos da requisição, e com base na classe que veio na requisição ir setando na entidade via reflection.
O problema é quanto aos converters, tem algum meio de chamar os conversores do vRaptor?

Seria +/- assim:

Class entity = Class.forName(PACKAGE + WordUtils.capitalize(entidade)); //entidade vem da requisição tambem
		
		try {
			
			Object obj = entity.newInstance();
			Enumeration<String> attrs = req.getParameterNames();
			while (attrs.hasMoreElements()) {
				
				String attrName = (String) attrs.nextElement();
				Field field = entity.getDeclaredField(attrName);
				Class<?> type = field.getType();
				
				entity.getMethod("set" + WordUtils.capitalize(attrName), type).invoke(obj, req.getParameter(attrName)); // aqui no invoke o parametro deve estar convertido para o tipo da entidade
			}

(código não testado)

Daria pra fazer o inverso também: pegar todos os atributos da entidade e procurar por eles na requisição. Não sei qual seria melhor.

Dá certo?

Lucas_Cavalcanti

seria esse componente:

vc deveria sobrescrever o array de parameter types passando a classe que vc sobrescreveu.

Criado 16 de janeiro de 2013
Ultima resposta 17 de jan. de 2013
Respostas 9
Participantes 3