2015-12-05 18 views
8

Vorrei trovare o creare un programma di caricamento classe Java che carichi solo le classi di sistema, escludendo tutte le classi nel percorso classe definito dell'applicazione. Il mio obiettivo è quello di utilizzare quel programma di caricamento classi per creare un programma di caricamento classe che carichi da un file JAR specifico, risolvendo le classi di sistema usando il caricatore di classi di solo sistema, ma senza contaminare le classi dal file JAR con le classi definite dalla mia applicazione.È necessario un caricatore classe di solo sistema Java

Finora non ho trovato alcun modo per creare un caricatore di classi di solo sistema che non utilizza API private o fa ipotesi sull'implementazione di Java. Vedi il codice qui sotto che funziona nel mio ambiente corrente ma fa ipotesi indesiderate.

Se non è possibile creare un caricatore di classe di solo sistema indipendente dall'implementazione, esiste un motivo per cui no? È quello che sto cercando di fare una cattiva idea?

private ClassLoader createJarClassLoader(File f) 
{ 
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 
    if (systemClassLoader instanceof URLClassLoader) { 
     URLClassLoader cl = (URLClassLoader) systemClassLoader; 
     URL[] urls = cl.getURLs(); 
     List<URL> wantedURLs = new ArrayList<>(); 
     for (URL u : urls) { 
      if (isSystemURL(u)) { 
       wantedURLs.add(u); 
      } 
     } 
     try { 
      wantedURLs.add(f.toURI().toURL()); 
     } catch (MalformedURLException ex) { 
      return null; 
     } 
     return new URLClassLoader(wantedURLs.toArray(new URL[0]), null); 
    } 
    return null; 
} 

private boolean isSystemURL(URL u) 
{ 
    return u.getPath().contains("/jre/"); 
} 
+2

perché stai provando a fare questo? cosa stai cercando di ottenere? – jtahlborn

+0

@jtahlborn Ha dato le sue ragioni molto chiaramente: "Il mio obiettivo è ..." – qqilihq

+1

@qqilihq - no, l'OP ha descritto "cosa" stava cercando di raggiungere, non "perché" – jtahlborn

risposta

1

È necessario impostare il ClassLoader padre come bootload ClassLoader. Chiamare getClassLoader() su un oggetto java.lang.String per ottenere il bootload ClassLoader e utilizzarlo nel costruttore ClassLoader.

public class MyClassLoader extends URLClassLoader { 

    protected MyClassLoader(URL[] urls, ClassLoader parent) { 
     super(urls, parent); 
    } 

    static MyClassLoader getInstance(URL[] urls) { 
     ClassLoader parent = "".getClass().getClassLoader(); 
     return (new MyClassLoader(urls, parent)); 
    } 
} 

La rappresentazione del classloader di bootstrap è documentato come carico di attuazione

Alcune implementazioni possono utilizzare null per rappresentare la classe bootstrap. Questo metodo [getClassLoader] restituirà null in tali implementazioni se questa classe è stata caricata dal loader della classe bootstrap.

ma la stessa dicitura si applica a ClassLoader padre nel costruttore ClassLoader, il che significa che questa soluzione è portatile.

+0

Anche se (principalmente) funziona in JDK 8, lì non garantisce che il programma di caricamento classe bootstrap conosca tutte le classi nella piattaforma Java; nel JDK modulare progettato per JDK9, sicuramente non lo farà. La domanda più interessante è cosa significa nulla quando viene passato al costruttore ClassLoader. Non ho trovato alcuna specifica di cosa significhi, ma forse potrebbe essere definito implicare un programma di caricamento classe che conosce esattamente le classi nella piattaforma Java, né più né meno. –