Carregar classes de outro projeto usando um classloader próprio [RESOLVIDO]

1 resposta
laudenpower

Olá pessoal, tudo bem?

Bom antes de apresentar minha dúvida, apresento meu problema.

Eu estou fazendo um projeto onde eu quero mapear classes feitas em outros projetos de acordo com o padrão DAO, nesse caso esse mapeamento será feito usando JDBC (com PreparedStatement’s e tudo mais que tiver direito). Acontece que nas pesquisas que andei fazendo, vi que para poder manipular classes externas ao projeto em tempo de execução eu precisaria criar um classloader próprio (já li o tuto aqui do guj) e carregar essas classes de um jar para o meu projeto. Até aí tudo bem, pesquisando mais ainda consegui criar uma forma de adicionar arquivos .class dentro de um jar, sendo que esse jar eu salvo na pasta do projeto e em seguida passo ao objeto do tipo URLClassLoader que criei. O primeiro problema é que esses arquivos .class estão dentro de um pacote (pasta) e o código que tenho para gerar o jar aceita apenas 1 diretório contendo todos os .class dentro, nesse caso se tiver outra pasta (pacote) dentro ele não aceita, dá uma Exception dizendo que o arquivo tal é um diretório, só que as classes que eu estou adicionando tem no seu cabeçalho o nome do pacote a que pertence, logo o código que cria o Jar coloca as classes todas compactadas dentro do jar sem respeitar a pasta (pacote) em que estavam.
E o problema final. Depois que tudo foi criado e adicionado quando uso Reflection para “depenar” a classe o classloader não encontra ela, mas isso foi testado com 6 classes dentro de um jar e o mais estranho é que apenas 1 classe foi encontrada! Resumindo usando o comando classloader.loadClass("<nome_do_pacote.nome_da_classe>"), de 6 classes apenas uma encontra as demais não encontra e dá ClassNotFoundException, sendo que nesse caso se eu não coloco o pacote onde a classe foi criada o programa lança outra exceção dizendo que o nome da classe está errado apontando o nome dela mais o pacote a que ela pertence.
Então minha dúvida (finalmente) é: como posso adicionar classes externas de modo dinâmico ao meu projeto, para depois com o uso de reflection descobrir seus métodos?

Antes para dar uma clareada segue o método que gera o jar e adiciona o mesmo ao classloader.

public void createJarArchive(File archiveFile, File[] tobeJared) {
        try {
            
          byte buffer[] = new byte[10240];

          // Abre o arquivo
          FileOutputStream stream = new FileOutputStream(archiveFile);
          JarOutputStream out = new JarOutputStream(stream, new Manifest());

          for (int i = 0; i < tobeJared.length; i++) {
            if (tobeJared[i] == null || !tobeJared[i].exists() || tobeJared[i].isDirectory())
              continue; // Just in case...
            System.out.println("Adicionando ao jar:" + tobeJared[i].getName());

            // Adiciona o arquivo ao jar            
            JarEntry jarAdd = new JarEntry(tobeJared[i].getName());
            jarAdd.setTime(tobeJared[i].lastModified());
            out.putNextEntry(jarAdd);

            // Salva o arquivo
            FileInputStream in = new FileInputStream(tobeJared[i]);
            while (true) {
              int nRead = in.read(buffer, 0, buffer.length);
              if (nRead <= 0)
                break;
              out.write(buffer, 0, nRead);
            }
            in.close();
          }

          out.close();
          stream.close();
          System.out.println("Criação do jar completa");
        } catch (Exception ex) {
          ex.printStackTrace();
          System.out.println("Error: " + ex.getMessage());
        }
    }

A seguir a classe que representa o classloader

package util;

import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * Arquivo criado em: 09/07/2010
 * @author Laudelino Martins Cardoso Neto
 */
public class CarregadorDeClassesUtil extends URLClassLoader{

    private String urlPath;  

    public CarregadorDeClassesUtil() {
        super(new URL[]{});
    }
    
    //Adiciona o jar
    public void addJarFile (String path){
       try{
            urlPath = "jar:file://" + path + "!/";
            addURL(new URL(urlPath));
        }catch (Exception e) {
            e.printStackTrace();
            ArquivosUtil.gravarLog(DiversosUtil.getMensagemExcecao(e), ArquivosUtil.LOG_TIPO_ERRO);
        }
    }   
   
    //Com base no nome da classe tenta descobrir seus métodos
    public void listarMetodosDaClasse(String nomeDaClasse){
        try {
            
            Class c = this.loadClass(nomeDaClasse);                        
            Method m[] = c.getDeclaredMethods();

            for (int i = 0; i < m.length; i++) {
                System.out.println(m[i].toString());
            }
            
        }catch (Throwable e) {
            System.err.println(e);            
        }
    }
    
    //Método que lista os .class dentro do jar criado
    public List getClasseNamesInPackage(String jarName){
        ArrayList listaDeClasses = new ArrayList ();
        
        try{
            JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
            JarEntry jarEntry;

            while(true) {

                jarEntry = jarFile.getNextJarEntry ();
                    if(jarEntry == null){
                        break;
                }
                
                listaDeClasses.add(jarEntry.getName().replaceAll("/", "\\."));

            }
       }catch( Exception e){
         e.printStackTrace ();
       }

       return listaDeClasses;
    }

}//Fim da classe CarregadorDeClassesUtil

Desde já agradeço a atenção de todos e aguardo retorno :slight_smile:

1 Resposta

laudenpower

Apesar de ninguém ter comentado nada, mas para poupar possíveis futuros esforços, gostaria de dizer que consegui resolver e a solução foi simples: Na hora de criar o jar eu tenho que criar com o mesmo pacote que está criado no projeto dessa forma quando eu passo o nome do pacote mais o nome da classe no método classloader.loadClass() o classloader encontra a classe dentro do jar que eu adicionei.

Criado 13 de julho de 2010
Ultima resposta 13 de jul. de 2010
Respostas 1
Participantes 1