Classloader: adicionando classe ao classpath em runtime

3 respostas
Y

Boa tarde, pessoal do GUJ!

Estou fazendo aqui, por questões de praticidade (?!), uma pequena configuração no Windows para que eu possa rodar classes com 2 cliques.

Criei um arquivo bat com o seguinte:

cd C:\Java
java RunClass %1

Então, configurei o Windows para que, quando o usuário der 2 cliques sobre o arquivo *.class, o comando acima seja chamado, passando o path do arquivo para a minha classe RunClass.

Minha classe RunClass está assim:

import java.lang.reflect.Method;
import java.io.File;

public final class RunClass
  {
   public static void main(String[] args)
     {
      String className = (new File(args[0])).getName().replace(".class", "");
      (new RunClass()).runIt(className);
     }

   public void runIt(String className)
     {
      try
        {
         Class classPoint = Class.forName(className);
         Method method = classPoint.getMethod("main", new Class[] { String[].class });
         method.invoke(classPoint.newInstance(), new Object[] { new String[] { } });
        }
      catch(Exception e)
        { e.printStackTrace(); }
     }
  }

O fato de eu estar criando um objeto File e então pegando o nome é que, quando o Windows passa um nome de arquivo para uma aplicação, este nome vai formatado em formato DOS. Exemplo: C:\ARQUIV~1\FOLDER0~1\NOMEDA~1.CLASS
Para solucionar, usei o objeto File pra pegar o nome corretamente.

O Windows está passando o nome corretamente e a aplicação está chamando o método main perfeitamente. O problema (que eu não havia pensando quando tive a idéia de fazer a classe) é que o classpath não estará incluindo a pasta do arquivo *.class que estou tentando executar.

Eu li o tutorial sobre Classloader do GUJ mas não entendi muito bem como eu poderia usar nesse meu caso.

P.S.: é meio estranho que, para carregar uma classe, eu tenha de estar carregando outra primeiro, eu sei. Já pensei em fazer isso com o Runtime, mas preferi fazer assim para praticar um pouco de Reflection. Ah, também estou ciente de que essa minha classe só carregará classes que estejam no pacote-padrão.

Como eu adiciono uma pasta ao classpath em tempo de execução?

3 Respostas

rc1

Tu não adicionas. Ao menos não no classpath usado pelo classloader que carrega a tua aplicação, esse é predefinido (com o uso da opção -classpath ou -cp ou da variável de ambiente CLASSPATH).

O que tu consegues fazer é a partir da classe que inicia a aplicação, carregar uma outra classe com um classloader customizado. Aí, para esse classloader, tu podes definir o classpath em tempo de execução.

Para criar um classloader com um classpath arbitrário tu podes usar o java.net.URLClassLoader já existente:

URL[] meuClassPath = (...);
ClassLoader customLoader = new URLClassLoader(meuClassPath);

[Dica: para obter URLs a partir de strings que decrevem paths podes usar new File(stringPath).toURL()]

Por default, um classloader tem o classloader da aplicação (systemClassloader) como pai. Assim, o classpath do classloader customizado é tudo o que estiver em ‘meuClassPath’ mais o que já existe no classloader da aplicação.

Para usar esse classloader ao invés do classloader padrão na hora de carregar a classe, usa a versão de Class#forName() que recebe o classloader a ser usado como argumento.

(...)
Class classPoint = Class.forName(className, true, customLoader);
(...)
Y

Valew cara. Eu não entendi completamente o que terei de fazer, mas vou pesquisar mais por Classloaders e seguir as dicas que me destes.

Obrigado!

bebad

:shock:
Nossa, é tão complexo que eu tb fiquei sem entender, mas curti muito a ideia de poder configurar meu classpath sem ter que setar nenhuma variavel e sem reiniciar meu micro.

Valeu ! :stuck_out_tongue:

Criado 13 de maio de 2007
Ultima resposta 15 de mai. de 2007
Respostas 3
Participantes 3