¿Hay alguna manera de obligar a un cargador de clases a cargar un paquete incluso si ninguna de sus clases se ha cargado?
-
08-07-2019 - |
Pregunta
Digamos que una base de código java tiene un paquete llamado " com.example " ;.
En tiempo de ejecución, podemos obtener este paquete llamando
Package p = Package.getPackage( "com.example" ); //(returns null)
o incluso obtener una lista de todos los paquetes llamando
Packages[] ps = Package.getPackages();
El problema es que si el ClassLoader aún no ha cargado ninguna clase del paquete, no estará disponible para estas llamadas de función. Podemos forzarlo a cargar el paquete al cargar primero una de las clases del paquete, de esta manera:
this.getClass().getClassLoader().loadClass( "com.example.SomeClass" );
Package p = Package.getPackage( "com.example" ); //(returns non-null)
Sin embargo, esto es hacky y requiere conocer de antemano el nombre de alguna clase que pertenece al paquete.
Entonces, la pregunta es: ¿hay alguna forma de obtener una instancia de Package por nombre, independientemente de si ClassLoader ha hecho algo o no? ¿Son precisas mis suposiciones acerca de cómo la carga de clases / paquetes parecen funcionar en esta situación?
Solución
Supongo que necesita esto porque necesita inspeccionar sus anotaciones. De lo contrario, no le interesaría tener una referencia de paquete cuyas operaciones solo están relacionadas con el acceso a las anotaciones. Esto lleva a la suposición de que también tiene un paquete-info.java definido allí con algunas anotaciones.
Si marca java.lang.Package
verá que getPackageInfo
solo carga la clase de información del paquete como una clase ordinaria.
Tuve el mismo problema y se me ocurrió esta solución.
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);
}
Otros consejos
Alternativamente, podría usar el directorio raíz de la clase como punto de partida y recorrer todos los archivos y subdirectorios * .class. Esto solo funcionaría si sabe de antemano dónde residirán todos sus archivos .class.
La causa de todo esto es que Java tiene una carga de clase dinámica, por lo que las clases se pueden cargar en tiempo de ejecución desde ubicaciones desconocidas en el momento de la compilación o incluso en el momento del inicio. Por lo tanto, el concepto de un paquete es solo un espacio de nombres para las clases cargadas, no un directorio que puede usar para buscarlas.
Me temo que sus suposiciones no son válidas. Los cargadores de clases hacen la contabilidad de paquetes a medida que cargan clases.
Puede pasar un comodín a ClassLoader.getResources
y obligarlo a seleccionar las clases en un paquete, que a su vez hará el trabajo.
Puede hacer su propio ClassLoader que llame a definePackage
, pero eso no lo ayudará con los cargadores de clases habituales en uso.