Executar um metodo dinamicamente - Tem Jeito?

Imaginemos o seguinte metodo:

public String pesquisaMetodoAExecutar (pOperacao){
  
  operacao       op   =  new operacao();
  operacaoDAO dao =  new operacaoDAO();
  op                       = dao.searchOperacao(pOperacao);
  
  
  /*Esse retorno seria o nome de um metodo. Tem como pegar esse retorno
     que é uma String e mandar ele executar ? Tipo.. */
  
    executa_lang.peste( op.getMetodoParaExecutar());  /* Ou */
    vai_vai_nowww(op.getMetodoParaExecutar()); 
     
 
    Ou esse tipo de prática não é muito usada :-)
    São as minhas duas dúvidas do mês !
    Mês que vem tem mais rs
  
 
   return "X";
}

não sei se é oque eu entendi direito, mas procure estudar sobre reflect

O amigo aí em cima está certo. Estude a API Reflection do Java. Com isso você poderá escolher o método que deseja executar dinamicamente.
Outra coisa, usar essa API em projetos deixa a execução mais lenta. Então cuidado com o excesso de reflexão no sistema para não perder performance…

[]'s.

Oi galera,

Então…também acho que com a API Reflection isso pode ser resolvido, aliás ouvi dizer que fizeram alguns ajustes na API e o problema da lentidão foi resolvido.

O problema que vejo no uso de Reflection são as loucuras que o individuo pode fazer, gerando alguns códigos bem difíceis de manter.
Resumindo…acho que SE NÃO HOUVER OUTRO JEITO use MODERADAMENTE seguindo BOAS PRÁTICAS DE PROGRAMAÇÃO.

[]'s

Galera, obrigado pela ajuda.

Vou tomar cuidado ao usar isso. Acredito que só irei precisar uma vez… pois eu monto uma TREE com alguns links. Cada link é uma pagina e para cada pagina existe um metodo que preenche um list. Entao para nao fazer um monte de IF vou usar essa pratica… mas pode deixar que vou estudar direitinho.

Obrigado amigos.

Galera, vou complicar um pouco.
Tentei implementar o procedimento da forma que vocês me falaram… e não consegui. Vejam se o problema esta porque estou fazendo isso com manager-bean.

1- Tenho um backing-bean chamado asController
2 - Tenho um backing-bean chamado geController
3 - Faço sempre uma injeção de dependencia do geController para o asController: Sendo assim temos:

/* Manager Bean asController */
public class asController {

    //Injeção de Dependências    
    private geController           geController;   
 
}

4 - Dentro do asController faco um select no banco de dados para pegar a coluna que possui a classe e o metodo a ser executado. Nessa coluna
já tentei cadastrar de tudo quanto é jeito:

 Caminho todo:    br.com.websis.controller.geController.search();
 Só o apelidinho:  geController.search();
 Sem os parenteses: .search()

 Enfim .. não funciona.

5 - Segue abaixo o meu código que é utilizado para chamar o tal metodo, e também o erro que está me aparecendo: Coloquei os valores fixos
para melhorar o entendimento.

  [code]
   /*Carrega a classe que esta cadastrada na operacao*/
    Class clazz   = Class.forName("geController");   
  
    Object object = clazz.newInstance();
    Method method = clazz.getMethod("gePaisSearchAll()",clazz);
  
     String desc  = (String) method.invoke(object,object); 

 [/code]


Erro: javax.faces.el.EvaluationException: java.lang.ClassNotFoundException: geController 

6 Quando coloco o caminho todo ele diz que não encontrou o metodo.
Aguardo amigo uma ajudinha, porque sinceramente não sei o que fazer

Vamos por partes

/*Carrega a classe que esta cadastrada na operacao*/ Class clazz = Class.forName("geController");

O parâmetro de Class.forName() deve ser o nome completo da classe. Se ela estiver em algum pacote, o nome do pacote deve ser incluído.

Além disto, não vejo necessidade em carregar a classe assim, se você pode simplesmente fazer geController.class.

Object object = clazz.newInstance();

Ok, desde que geController tenha um construtor sem parâmetros ou nenhum construtor definido.

Method method = clazz.getMethod("gePaisSearchAll()",clazz);

Os parênteses não são incluídos no nome do método.

String desc  = (String) method.invoke(object,object);

O primeiro parâmetro de invoke() é o objeto para o qual o método será invocado, o segundo um vetor contendo os parâmetros.

É bom você ler sobre Reflection. Aqui tem um tutorial em português sobre o assunto.

Hummm…vc disse que quando coloca o caminho da classe e o erro informado é sobre método não encontrado, isso é um bom sinal porque quer dizer que o objeto foi criado corretamente e está pronto para uso.

Olhando rapidamente notei que você escreveu o nome do método desse jeito: “gePaisSearchAll()” será que o nome do método não está errado? Vai ver o nome do método é “getPaisSearchAll()” ou sei lá.

Dica: Sempre use copy paste nestes casos, não confie nos seus olhos e dedos.

[]'s

só complementando… em:

Method method = clazz.getMethod("gePaisSearchAll()",clazz); 

o segundo parametro tem que ser um vetor contendo as classes dos parametros que seu metodo recebe

assim… se seu metodo é ex:
public void gePaisSearchAll(String nome, Integer id)

a chamada teria de ser:

Method method = clazz.getMethod("gePaisSearchAll", new Class[] {String.class, Integer.class});
//ou da nova forma
Method method = clazz.getMethod("gePaisSearchAll", String.class, Integer.class);

Galera, estamos quase ! Faltou algo que não ficou claro.
Seguindo a explicão do nosso caro companheiro Rodrigo Manhães eu consegui fazer a execução de um metódo de forma dinanica, como gostaria. O problema é o seguinte. Lembra que eu comentei que as duas classes são manager-beans ? Pois então… quando eu executo dinamicamente passando o caminho todo da classe, ele nao faz a injeção de dependencias.

Vou explicar melhor dando exemplos. Sigam comigo:

1 - Backing Bean geController.

public class geController {
    
    /** Contrutor */
    public geController() {
    }

    /*Metodo responsavel por efetuar a busca na tabela de pessoa*/
    public String gePaisSearchAll() {
        try {

            gePaisDAO gePaisDAO = new gePaisDAO();
            this.setGePaisList(gePaisDAO.searchAll());

            return "gePaisSearchAllSucess";

        } catch (Exception ex) {
            ex.printStackTrace();
            return "gePaisSearchAllError";
        }
    }
  
   //Gets e Sets
  

}

2 - Agora tenho o meu asController que também é um Backing Bean


public class asController {

    //Injeção de Dependências    
    private geController           geController;   

    /** Contrutor. */
    public asController() {
    }

    /*Metodo ESTATICO - QUERO FAZER ISSO DINAMICAMENTE*/
    public String callOper() {
      this.geController.gePaisSearchAll();
      return "ok";
    }

   /*Metodo DINAMICO - COMO FAZER ? Conforme o codigo abaixo ele funciona mas nao usa o geController que utliza a injecao de dependencia
     */
    public String callOper() {

        /*Carrega a classe que esta cadastrada na operacao*/
        Class  classe   = Class.forName("websis.controller.ge.geController");  
        Object objeto   = classe.newInstance();
        Method metodo   = classe.getMethod("gePaisSearchAll");
        String desc     = (String) metodo.invoke(objeto);
        return "ok";
    }

}

3 Faces Config com a Injecao de Dependencias:

<managed-bean>
        <managed-bean-name>asController</managed-bean-name>
        <managed-bean-class>websis.controller.as.asController</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
        <managed-property>
            <property-name>geController</property-name>
            <value>#{geController}</value>
        </managed-property>
    </managed-bean>

Obrigado pela atencao dos Senhores.
So falta isso pra eu terminar o meu menu baseado na TREE do richfaces.
Obrigado amigos.

Desculpe a curiosidade,

mas porque você não usa interface, tipo criar uma interface para esse método que existe em todos os seus links…

Quando eu deixei de programa em C e comecei em java eu sempre procurava uma maneira de como criar um ponteiro para uma função, e depois vi que em OO é mais fácil se trabalhamos com interfaces.

fw

Boa noite ,

Qualquer ajuda é sempre bem vinda. Como assim usar Interface ?
Tenho tenho alguns metodos cadastrados no banco de dados e quero executa-los de forma dinamica. Na situação em que eu parei achei que estava fácil. Estou desde cedo em cima disso e não consigo terminar.

Minha ultima tentativa foi essa ai.

                    /*Carrega a classe que esta cadastrada na operacao*/
                    Class classe   = Class.forName("websis.controller.as.asController");
                    
                    /*Instancia a classe.*/
                    Object objeto = classe.newInstance();
                    
                    /*Como o atributo e uma referencia, entao teremos que executar um 
                    metodo que esta dentro do atributo.*/
                    Method metodo   = classe.getMethod("getGeController.gePaisSearchAll");
                    retorno = (String) metodo.invoke(objeto);
                    return  retorno;

Mas dá o erro:
java.lang.NoSuchMethodException: websis.controller.as.asController.getGeController.gePaisSearchAll()
Que está certo na verdade, porque no meu asController eu não tenho esse metodo:getGeController.gePaisSearchAll()

O metodo gePaisSearchAll() está dentro do geController.
Que coisa viu

Deixa eu tentar entender melhor o seu problema, para pode explicar melhor a minha idéia.

[quote]Obrigado pela atencao dos Senhores.
So falta isso pra eu terminar o meu menu baseado na TREE do richfaces.
Obrigado amigos. [/quote]

Seria mais ou menor como criar um menu e para cada item desse menu eu dizer quem é o pai (tree) e quando ele fosse selecionado e não tivesse filho chamasse um método qualquer de uma classe qualquer.

E o nome da classe e o respectivo método são informações mantidas em um banco de dados.

[quote]4 - Dentro do asController faco um select no banco de dados para pegar a coluna que possui a classe e o metodo a ser executado. Nessa coluna
já tentei cadastrar de tudo quanto é jeito: [/quote]

Então vamos ao pressuposto 1: a sua aplicação é como um coponente que será usado por outro sistema, esse outro sistema é que irá definir os itens e as respectivas ações a serem executadas.

Bom nesse caso, o meu palpite é que você quer fazer algo similar o que as classes javax.swing.JMenu e javax.swing.JMenuItem fazem utilizando a interface ActionListener.

correto?

fw

[code]/*Metodo DINAMICO - COMO FAZER ? Conforme o codigo abaixo ele funciona mas nao usa o geController que utliza a injecao de dependencia
*/
public String callOper() {

     /*Carrega a classe que esta cadastrada na operacao*/  
     Class  classe   = Class.forName("websis.controller.ge.geController");    
     //Object objeto   = classe.newInstance();   <- você está criando uma nova instancia de geController aki
     Object objeto = this.getController; // <- assim voce pega o geController que está na variavel geController. obs: nome da variavel igual nome da classe??
     Method metodo   = classe.getMethod("gePaisSearchAll");  
     String desc     = (String) metodo.invoke(objeto);  
     return "ok";  
 }  [/code]

Se a idéia do jukkinha não rolar tente esta:

                    /*Carrega a classe que esta cadastrada na operacao*/
                    Class classe   = Class.forName("websis.controller.as.asController");
                    
                    /*Instancia a classe asController.*/
                    Object objeto = classe.newInstance();
                    
                    /*Obter o método que retorna a instancia da classe geController*/
                    Method metodo   = classe.getMethod("getGeController");

                    /*Obter a instancia gerada pela classe geController*/
                    Object g = metodo.invoke(objeto);

                    /*Obter o método gePaisSearchAll que está na classe geController*/
                    Method m   = g.getClass().getMethod("gePaisSearchAll");

                    /*Obter o retorno da método gePaisSearchAll*/
                    retorno = (String) m.invoke(g);

                    return  retorno;

P.S. Posso estar enganado mas acho que não é possível a execução de métodos por reflexão em objetos associados diretamente, se isso for verdade (não testei :oops: ) a mesagem de erro está correta.

[]'s

Jukkinha,

Funcionou blz, o problema é que o metodo getController precisa ser dinamico também.
Como fazer ?

//Object objeto   = classe.newInstance();   <- você está criando uma nova instancia de geController aki   
  Object objeto = this.getController; 

fantomas,

O seu exemplo só não funcionou legal, porque você criou uma nova instancia. Se não criar essa nova instancia acho que funciona… mas como chamar o invoke sem passar o objeto ?

O jeito que o Jukkinha passou, funcionou também, mas ele faz um this.getController ( Por isso que funciona ) e esse getController precisar ser dinamico.

Oi Iblanco,

 [quote]O seu exemplo só não funcionou legal, porque você criou uma nova instancia[/quote]

  O único lugar que está sendo gerada uma instancia é nesta linha que já estava presente no código que vc postou.
                    /*Instancia a classe asController.*/
                    Object objeto = classe.newInstance();
 As linhas que adicionei não geram instancias, há não ser que os métodos que são executados estejam fazendo isto.

 Acho que não entendi direito, vc poderia detalhar  :?: 

Abraços

Claro meu amigo. Primeiramente gostaria de agradecer a sua ajuda. Acredita , está sendo muito importante.
Vamos lá:

1 - O Código que você postou é esse:

/*Carrega a classe que esta cadastrada na operacao*/   
Class classe   = Class.forName("websis.controller.as.asController");   
  
/*Instancia a classe asController.*/   
Object objeto = classe.newInstance();   
  
/*Obter o método que retorna a instancia da classe geController*/   
Method metodo   = classe.getMethod("getGeController");   
  
/*Obter a instancia gerada pela classe geController*/   
Object g = metodo.invoke(objeto);   
  
/*Obter o método gePaisSearchAll que está na classe geController*/   
Method m   = g.getClass().getMethod("gePaisSearchAll");   
  
/*Obter o retorno da método gePaisSearchAll*/   
retorno = (String) m.invoke(g);   
  
return  retorno;  

Ele está funcionando perfeitamente. O único problema é que, quando usamos o:

Object objeto = classe.newInstance();

ele cria outra instancia da classe. Quando é criada essa nova instancia , ele não usa o framework do JSF que faz a injeção de dependencias e assim a classe executa o metódo porém em outro contexto.

De acordo com o post do Jukkinha funcionou também. Ele não cria uma nova instancia, porém ele utiliza o getController fixo e eu queria fazer isso dinamicamente. Para ser mais claro imagine o seguinte contexto:

1 - tabela do banco com as seguintes colunas:

ID : 1
Classe : br.com.nossoteste.asController
Atributo: null
Metodo: null

ID : 2
Classe : br.com.nossoteste.geController
Atributo: geController
Metodo : gePaisSearchAll

2 Quando a classe asController é instanciada pelo JSF ela injeta a geController.

3 Classe asController simples:

   public class asController{

   geController ge; 
   // gets e sets

   // Executa dinamicamente o metodo
   public String executa(){
     
      tabelaDAO tab=  new tabelaDAO ();
      classeTabela tabModel = new classeTabela ();

      tabModel = tabelaDAO.query(2); // Passando o ID.
     
     /*Teriamos o retorno
     
    tabModel.getId = 2
    tablModel.getClasse  = br.com.nossoteste.geController
    tabModel.getAtributo = geController
    tabModel.gePaisSearchAll.

    Agora gostaria de com esses valores usar a api Reflection para rodar 
    esse metodo gePaisSearchAll. 
     */
      
   }
  
}

Galera, ficou mais claro agora a minha explicação.
Obrigado pela ajuda dos senhores. Assim como postei os códigos da TREE prometo postar a resolução desse problema, pois acredito que será de grande utilidade para todos.

Obrigado pela ajuda.
Abraços

Galera , salve salve…

Um amigo que trabalha comigo ( Wenceslau ), resolveu o problema… Fiquei até envergonhado, pois gastei o domingo todo nisso e ele me 40 minutos matou o problema.

Segue abaixo o código:

                   Method metodo   = this.getClass().getMethod("getGeController");
                   Object obj = metodo.invoke(this);
                   
                   
                   Method met2 = obj.getClass().getMethod("gePaisSearchAll");
                   retorno = (String)met2.invoke(obj);
                   
                   return retorno;

Abraços