Domanda

Sto scrivendo uno strumento di analisi statica per un incarico, analizza il bytecode Java utilizzando la libreria ASM. Una delle parti di ASM che usiamo richiede (o almeno, sembra richiedere) che la classe essere caricata dal ClassLoader.

Speravamo lo strumento sarebbe in grado di analizzare i file .class senza richiedere loro nel classpath. Abbiamo già carichiamo i .classes da una directory specificata in fase di esecuzione e leggerli utilizzando un InputStream. Questo è accettabile per ASM nella maggioranza dei casi. Ci sono alcune classi, come SimpleVerifier, che tentano di caricare le classi però.

E 'possibile, in questo scenario, per registrare i file .class da caricare in modo che le chiamate a Class.forName() li caricherà? O c'è un modo semplice per estendere la ClassLoader permettere questo?


Edit: le informazioni sul URLClassLoader era utile. Purtroppo, utilizzando Thread.currentThread().setContextClassLoader() a un'istanza di che non ha funzionato in questo scenario. Il codice della libreria che sto mettendo in usa un caricatore si recupera su istanza di inizializzazione utilizzando getClass().getClassLoader().

Con il tempo ho impostato l'URLClassLoader la classe non è stato inizializzato quindi credo che il contextClassLoader non carica quella classe.

Ho forse capito bene le risposte? Sarebbe utilizzando l'URLClassLoader per caricare la classe 3a parte essere una possibilità?

È stato utile?

Soluzione

Quasi.

Se avete classi compilate da qualche parte, è possibile caricare con un URLClassLoader . È quindi possibile impostare questa ClassLoader essere il ClassLoader per il thread corrente: Thread.setContextClassLoader (ClassLoader)

Gli utenti possono ottenere che il caricatore discussioni attuali classe contesto e l'uso che per accedere alla definizione di classe.

Altri suggerimenti

Prima di tutto, ASM può essere utilizzato in un modo tale che non userà ClassLoader per ottenere informazioni sulle classi.

Ci sono molti posti in quadro di ASM in cui viene caricato classi di default, ma tutti quei luoghi può essere ignorata nelle vostre sottoclassi. Fuori della parte superiore della mia testa:

  • ClassWriter.getCommonSuperClass () metodo viene chiamato solo quando viene utilizzato ClassWriter.COMPUTE_FRAMES bandiera e può essere sovrascritto non utilizzare ClassLoader per ottenere inforamtion sulle classi. È possibile trovare un esempio di che nel ClassWriterComputeFramesTest che introduce un'astrazione ClassInfo
  • metodo Analogamente SimpleVerifier.getClass () è utilizzato da SimpleVerifier.isAssignableFrom () ed è possibile sovrascrivere quest'ultimo e utilizzare l'astrazione ClassInfo per trovare il comune Super. Se non mi sbaglio, progetto AspectWerkz aveva attuato cosa simile nel suo codice di tipo pattern matching. Si noti inoltre che non v'è SimpleVerifier.setClassLoader () metodo, che è possibile utilizzare se si vuole ancora di caricare le proprie classi.

Una nota a parte, su JVM di un Sole, classi caricate arriva a PermGen zona e non possono essere scaricati, quindi non è una buona idea per caricare le classi solo per scopi di analisi statica del codice se si può evitare che, soprattutto se strumento sarebbe essere integrato in un processo a lungo dal vivo, come ad esempio IDE.

Non è possibile, per quanto ne so, estendere la class loader del sistema in fase di esecuzione, ma è possibile caricare in modo dinamico le classi da una posizione arbitraria (vaso o directory) utilizzando URLClassLoader .

Si potrebbe provare a impostare un "launcher" in avvio dell'applicazione che crea un URLClassLoader passando le posizioni sul percorso di classe e le proprie sedi .class e avviare l'applicazione da quel classloader.

Quando il SimpleVerifier viene caricato dal URLClassLoader sarà anche in grado di caricare le classi dalle posizioni in più.

Sì, è possibile utilizzare URLClassLoader

Ho un test in cui io caricare la classe in fase di esecuzione. Questa classe non è nel classpath (e nemmeno esistere quando il test viene eseguito in questo caso), in seguito si è caricato e funziona alla grande.

Ecco il codice.

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!!
}

domanda .

Ho creato il mio ClassLoader è abbastanza semplice.

 /**
 * 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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top