C'è un modo per forzare un classloader a caricare un pacchetto anche se nessuna delle sue classi è stata caricata?
-
08-07-2019 - |
Domanda
Supponiamo che una base di codice java abbia un pacchetto chiamato " com.example " ;.
In fase di esecuzione, possiamo ottenere questo pacchetto chiamando
Package p = Package.getPackage( "com.example" ); //(returns null)
o anche ottenere un elenco di tutti i pacchetti chiamando
Packages[] ps = Package.getPackages();
Il problema è: se ClassLoader non ha ancora caricato alcuna classe dal pacchetto, non sarà disponibile per queste chiamate di funzione. Possiamo forzarlo a caricare il pacchetto caricando prima una delle classi nel pacchetto, in questo modo:
this.getClass().getClassLoader().loadClass( "com.example.SomeClass" );
Package p = Package.getPackage( "com.example" ); //(returns non-null)
Tuttavia, questo è hacky e richiede di conoscere in anticipo il nome di una classe che appartiene al pacchetto.
Quindi la domanda è: c'è un modo per ottenere un'istanza del pacchetto per nome, indipendentemente dal fatto che ClassLoader abbia fatto qualcosa? I miei presupposti su come i classload / pacchetti sembrano funzionare in questa situazione sono precisi?
Soluzione
Presumo che tu ne abbia bisogno perché devi ispezionarne le annotazioni. Altrimenti non ti interesserebbe avere un riferimento al pacchetto in cui solo le operazioni riguardano l'accesso alle annotazioni. Questo porta al presupposto che tu abbia anche un pacchetto-info.java definito lì con alcune annotazioni.
Se selezioni java.lang.Package
vedrai che getPackageInfo
carica semplicemente la classe di informazioni sul pacchetto come una normale classe.
Ho avuto lo stesso problema e ho trovato questa soluzione.
public static Package getPackage(String packageName) throws ClassNotFoundException {
Class.forName(packageName+".package-info"); // makes sure package info exist and that the class loader already knows about the package
return Package.getPackage(packageName);
}
Altri suggerimenti
In alternativa è possibile utilizzare la directory principale della classe come punto di partenza e scorrere tutti i file * .class e le sottodirectory. Funzionerebbe solo se sai prima dove risiederanno tutti i tuoi file .class.
La causa di tutto ciò è che Java ha un caricamento dinamico delle classi, quindi le classi possono essere caricate in fase di esecuzione da posizioni non note al momento della compilazione o anche al momento dell'avvio. Pertanto, il concetto di pacchetto è solo uno spazio dei nomi per le classi caricate, non una directory che è possibile utilizzare per cercarle.
Temo che i tuoi presupposti non siano validi. I classloader tengono la contabilità dei pacchetti mentre caricano le classi.
Puoi passare un carattere jolly a ClassLoader.getResources
e forzarlo a raccogliere le classi in un pacchetto, che a sua volta farà il lavoro.
Puoi creare il tuo ClassLoader che chiama definePackage
, ma ciò non ti aiuterà con i soliti classloader vanilla in uso.