Pergunta

Eu estou escrevendo uma ferramenta de análise estática para uma atribuição, analisa Java bytecode usando a biblioteca ASM. Uma das partes do ASM que usamos requer (ou, pelo menos, parece exigir) que a classe ser carregado a partir do ClassLoader.

Nós estávamos esperando que a ferramenta seria capaz de analisar .class arquivos sem a necessidade de-los no classpath. Já carregar os .classes de um diretório especificado em tempo de execução e lê-los em usar um InputStream. Isto é aceitável para ASM na maioria dos casos. Há algumas classes, como SimpleVerifier, que tentam carregar as classes embora.

É possível, neste cenário, para registrar os arquivos .class para ser carregados de modo que as chamadas para Class.forName() irá carregá-los? Ou há uma maneira fácil de estender o ClassLoader para permitir isso?


Edit: as informações sobre URLClassLoader foi útil. Infelizmente, usando Thread.currentThread().setContextClassLoader() a uma instância do que não funcionou neste cenário. O código da biblioteca Eu estou chamando para usos um carregador ele recupera na instância de inicialização usando getClass().getClassLoader().

Até o momento eu definir o URLClassLoader a classe não foi inicializado então eu acho que o contextClassLoader não carrega essa classe.

Have I compreender as respostas corretamente? Será que usando o URLClassLoader para carregar a 3ª classe festa seja uma possibilidade?

Foi útil?

Solução

Quase.

Se você tem aulas em algum lugar compilados, você pode carregá-los com um URLClassLoader . em seguida, você pode definir essa ClassLoader ser o ClassLoader para o segmento atual: Thread.setContextClassLoader (ClassLoader)

Os usuários podem obter que o carregador de tópicos atuais classe de contexto e usar isso para acesso a definição de classe.

Outras dicas

Em primeiro lugar, ASM pode ser usado de tal forma que ele não vai usar ClassLoader para obter informações sobre classes.

Há vários lugares em quadro ASM onde ele carrega as classes por padrão, mas todos esses lugares podem ser substituídas em suas próprias subclasses. Fora do topo da minha cabeça:

  • método ClassWriter.getCommonSuperClass () é chamado apenas quando o sinalizador ClassWriter.COMPUTE_FRAMES é usado e pode ser overwriten para não usar ClassLoader para obter inforamtion sobre classes. Você pode encontrar um exemplo de que em ClassWriterComputeFramesTest que introduz um ClassInfo abstração
  • De modo semelhante SimpleVerifier.getClass () método é utilizado por SimpleVerifier.isAssignableFrom () e você pode substituir o último e usar a abstração ClassInfo para encontrar o comum Super tipo. Se não me engano, projeto AspectWerkz tinha implementado algo semelhante em seu código do tipo de correspondência de padrão. Também nota que há SimpleVerifier.setClassLoader () método , que você pode usar se você ainda quer carregar suas próprias classes.

Em uma nota lateral, em JVMs um da Sun, classes carregadas começa a área de PermGen e não pode ser descarregado, por isso não é uma boa idéia para classes de carga única para fins de análise estática de código se você pode evitar isso, especialmente se ferramenta seriam integrados em um processo de longo vivo, tais como IDE.

Você não pode, tanto quanto eu sei, estender o carregador de classe do sistema em tempo de execução, mas você pode dinamicamente carregar classes de um local arbitrário (jar ou diretório) usando URLClassLoader .

Você poderia tentar configurar um "lançador" na inicialização do seu aplicativo que cria um URLClassLoader passando-as localizações no classpath e seus próprios locais .class e iniciar a aplicação a partir desse carregador de classe.

Quando o SimpleVerifier é carregado pelo URLClassLoader ele irá também ser capaz de carregar as classes a partir das localizações extra.

Sim, você pode usar URLClassLoader

Eu tenho um teste onde eu carregar a classe em tempo de execução. Esta classe não está no classpath (nem sequer existia quando o teste é executado para que o assunto), depois é carregado e funciona muito bem.

Aqui está o código.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

retirado deste questão .

Eu criei meu próprio ClassLoader seu bastante simples.

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top