Nous avons appris les notes de version de Java 9 que
L'application du chargeur de classe n'est plus une instance de java.net.URLClassLoader (un détail d'implémentation qui n'a jamais été spécifié dans les versions précédentes). Le Code qui suppose que le chargeur de classe::getSytemClassLoader retourne un URLClassLoader objet devra être mis à jour.
Cela rompt avec l'ancien code, qui scrute le classpath comme suit:
Java <= 8
URL[] ressources = ((URLClassLoader) classLoader).getURLs();
qui s'exécute dans un
java.lang.ClassCastException:
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to
java.base/java.net.URLClassLoader
Donc, pour Java 9+ la solution de contournement suivante a été proposée comme un PR Apache Enflammer Projet, qui fonctionne comme prévu compte tenu des ajustements dans la JVM options d'exécution: --add-opens java.base/jdk.internal.loader=ALL-UNNAMED
. Toutefois, comme mentionné dans les commentaires ci-dessous, ce RP n'a jamais été fusionnées dans leur branche Master.
/*
* Java 9 + Bridge to obtain URLs from classpath...
*/
private static URL[] getURLs(ClassLoader classLoader) {
URL[] urls = new URL[0];
try {
//see https://github.com/apache/ignite/pull/2970
Class builtinClazzLoader = Class.forName("jdk.internal.loader.BuiltinClassLoader");
if (builtinClazzLoader != null) {
Field ucpField = builtinClazzLoader.getDeclaredField("ucp");
ucpField.setAccessible(true);
Object ucpObject = ucpField.get(classLoader);
Class clazz = Class.forName("jdk.internal.loader.URLClassPath");
if (clazz != null && ucpObject != null) {
Method getURLs = clazz.getMethod("getURLs");
if (getURLs != null) {
urls = (URL[]) getURLs.invoke(ucpObject);
}
}
}
} catch (NoSuchMethodException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
logger.error("Could not obtain classpath URLs in Java 9+ - Exception was:");
logger.error(e.getLocalizedMessage(), e);
}
return urls;
}
Toutefois, cela provoque des maux de tête sévères en raison de l'utilisation de la Réflexion ici. C'est une sorte d'anti-modèle et est strictement critiqué par l' interdit-api de plugin maven:
Interdit d'invocation de méthode: java.lang.de réfléchir.AccessibleObject#setAccessible(boolean) [Réflexion d'utilisation pour travailler autour de l'accès des drapeaux échoue avec SecurityManagers et probablement ne fonctionnera plus sur les classes d'exécution de Java 9]
Question
Est-il sûr moyen d'accéder à la liste de toutes les ressources d' URLs
dans la classe / chemin d'accès du module, qui peut être consulté par le chargeur de classe, dans OpenJDK 9/10 sans l'aide d' sun.misc.*
des importations (par exemple en utilisant Unsafe
)?
Mise à JOUR (pour les commentaires)
Je sais, que je peux faire
String[] pathElements = System.getProperty("java.class.path").split(System.getProperty("path.separator"));
pour obtenir les éléments dans le chemin de la classe et puis les analyser pour URL
s. Cependant, autant que je sache - cette propriété renvoie uniquement le classpath donné au moment du lancement de l'application. Cependant, dans un récipient contenant de l'environnement ce sera la seule de l'application serveur et pourrait ne pas être suffisant, par exemple, puis à l'aide d'OREILLE ensembles.
Mise à JOUR 2
Merci beaucoup pour tous vos commentaires. Je vais tester, si System.getProperty("java.class.path")
de travail pour nos fins et de mise à jour de la question, si c'capable de réaliser nos besoins.
Cependant, il semble que d'autres projets (peut-être pour d'autres raisons, l'e.g Apache TomEE 8) subissent les mêmes douleurs liées à l' URLClassLoader
- pour cette raison, je pense que c'est une précieuses question.