Controller dinamico - vRaptor

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.

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.

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…

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…

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

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

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]

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

"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?

seria esse componente:

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