(JDK 11) Ejecutar un Archivo JAR través de la reflexión que depende de Bibliotecas

Liz3:

Nota : Tengo muy poca experiencia con el sistema de módulo introducido en Java 9.

Tengo un proceso de Java que debe ejecutar otro archivo Jar cargando y ejecutando a través de la reflexión. Tenga en cuenta que los dos archivos Jar dependen del marco JavaFX que consiguió separarse del JDK en la Versión 11 y como resultado podría conseguir cargado por segunda vez.

Aquí la versión original, que trabajó en JDK versión 8:

val ideFile = File(binFolder, "Sk-IDE.jar")
val classLoader = ClassLoader.getSystemClassLoader() as URLClassLoader
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
method.isAccessible = true
method.invoke(classLoader, ideFile.toURI().toURL())
val coreManager = Class.forName("com.skide.CoreManager")
val instance = coreManager.newInstance()
coreManager.getDeclaredMethod("bootstrap", Array<String>::class.java).invoke(instance, State.args)

(La llamada reflectante a AddURL era necesario porque de lo contrario el tarro cargador no ha podido cargar sus archivos fxml)

Este enfoque lanza esta excepción en JDK 11:

java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')

El enfoque para crear una nueva URLClassLoader:

val child = URLClassLoader(arrayOf(URL(ideFile.toURI().toURL().toString())), Installer::class.java.classLoader)
val coreManager = Class.forName("com.skide.CoreManager", true, child)
val instance = coreManager.newInstance()
Platform.runLater {
    coreManager.getDeclaredMethod("bootstrap", Array<String>::class.java).invoke(instance, State.args)
}

Emite una excepción relacionada JavaFX:

Exception in thread "JavaFX Application Thread" [20.11.2018 20:13:41 | ERROR] java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
[20.11.2018 20:13:41 | ERROR]   at java.base/java.security.AccessController.doPrivileged(Native Method)
[20.11.2018 20:13:41 | ERROR]   at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
[20.11.2018 20:13:41 | ERROR]   at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
[20.11.2018 20:13:41 | ERROR]   at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
[20.11.2018 20:13:41 | ERROR]   at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
[20.11.2018 20:13:41 | ERROR]   at java.base/java.lang.Thread.run(Thread.java:834)
[20.11.2018 20:13:41 | ERROR] Caused by: java.lang.reflect.InvocationTargetException
[20.11.2018 20:13:41 | ERROR]   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[20.11.2018 20:13:41 | ERROR]   at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[20.11.2018 20:13:41 | ERROR]   at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[20.11.2018 20:13:41 | ERROR]   at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[20.11.2018 20:13:41 | ERROR]   at com.skide.installer.Installer$start$2$1$1.run(Installer.kt:249)
[20.11.2018 20:13:41 | ERROR]   at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
[20.11.2018 20:13:41 | ERROR]   ... 6 more
[20.11.2018 20:13:41 | ERROR] Caused by: javafx.fxml.LoadException: 
unknown path:9

[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:105)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:930)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:980)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:227)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:752)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
[20.11.2018 20:13:41 | ERROR]   at com.skide.CoreManager$bootstrap$1.invoke(CoreManager.kt:47)
[20.11.2018 20:13:41 | ERROR]   at com.skide.CoreManager$bootstrap$1.invoke(CoreManager.kt:24)
[20.11.2018 20:13:41 | ERROR]   at com.skide.CoreManager.bootstrap(CoreManager.kt:136)
[20.11.2018 20:13:41 | ERROR]   ... 12 more
[20.11.2018 20:13:41 | ERROR] Caused by: java.lang.ClassNotFoundException: com.skide.gui.controllers.SplashGuiController
[20.11.2018 20:13:41 | ERROR]   at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
[20.11.2018 20:13:41 | ERROR]   at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
[20.11.2018 20:13:41 | ERROR]   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
[20.11.2018 20:13:41 | ERROR]   at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:928)
[20.11.2018 20:13:41 | ERROR]   ... 21 more

¿Cuál es la mejor manera de resolver esto?

Saludos, Liz3

EDITAR

Con la ayuda de xtratic, la solución era realmente sencillo:

I simplemente añadido el childURLClassLoader a la # bootstrap llamada reflectante CoreManager, el método de arranque de la CoreManager (frasco cargado) de pases que URLClassLoader a todos los cargadores FXML.

xtratic:

Cuando se está utilizando el nuevo URLClassLoaderparece que el método está siendo invocado, pero está lanzando una javafx.fxml.LoadExceptionque consigue envuelto por la PrivilegedActionExceptiony InvocationTargetException.

A pesar de que se carga la clase con su propio URLClassloaderparece que el analizador FXML está tratando de cargar los granos de FX con la incorporada en el cargador de clase, que no sabe de esas clases en el FXML.

Tendrá que hacer FXMLLoader utilizar el cargador de clase de derecho que contiene todas las clases referenciadas por el fxml . Lea la fuente de FXMLLoaderpara tener una idea de cómo se maneja la carga de clase. Puede que tenga que modificar la biblioteca haciendo la carga fxml si es posible. Mira en FXMLLoader.setClassLoader(urlClassLoader)o posiblemente el establecimiento de un SecurityManagermodo que la FXMLLoaderva a utilizar el cargador de clase llamando.


FXMLLoader.java

/**
 * Returns the classloader used by this serializer.
 * @since JavaFX 2.1
 */
@CallerSensitive
public ClassLoader getClassLoader() {
    if (classLoader == null) {
        final SecurityManager sm = System.getSecurityManager();
        final Class caller = (sm != null) ?
                Reflection.getCallerClass() :
                null;
        return getDefaultClassLoader(caller);
    }
    return classLoader;
}

private static ClassLoader getDefaultClassLoader(Class caller) {
    if (defaultClassLoader == null) {
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            final ClassLoader callerClassLoader = (caller != null) ?
                    caller.getClassLoader() :
                    null;
            if (needsClassLoaderPermissionCheck(callerClassLoader, FXMLLoader.class.getClassLoader())) {
                sm.checkPermission(GET_CLASSLOADER_PERMISSION);
            }
        }
        return Thread.currentThread().getContextClassLoader();
    }
    return defaultClassLoader;
}

Tenía una conjetura que Java11 puede haber cambiado de cargador de clases.

Vea este enlace (contenidos pegados a continuación)

Para la fundición URL Cargador de clases
de Java 9 y el sistema de módulos mejorados estrategia de carga de clases de la plataforma, que se implementa en un nuevo tipo y en Java 11 el cargador de clases de aplicación es de ese tipo. Esto significa que no es una URLClassLoader, más, así que el ocasional (URLClassLoader) getClass().getClassLoader()o (URLClassLoader) ClassLoader.getSystemClassLoader()secuencias ya no se ejecutará . Este es otro ejemplo típico en el que Java 11 es compatible hacia atrás en el sentido estricto (debido a que es un URLCassLoader no se especificó), sino que puede, sin embargo, la causa de la migración desafíos.

Los síntomas
Éste es muy obvio. Usted obtendrá una ClassCastException quejaba de que el nuevo AppClassLoader hay URLClassLoader:

Exception in thread "main" java.lang.ClassCastException:
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader
cannot be cast to java.base/java.net.URLClassLoader
    at monitor.Main.logClassPathContent(Main.java:46)
    at monitor.Main.main(Main.java:28)

Corrige
el cargador de clases fue probablemente arrojados a los métodos de acceso específica a URLClassLoader. Si es así, usted podría tener que hacer frente a algunos cambios serios.
...
Si ha utilizado el URLClassLoaderde usuario proporcionada código de carga dinámica (por ejemplo, como parte de una infraestructura plug-in) añadiendo a la ruta de clase, entonces usted tiene que encontrar una nueva manera de hacer eso, ya que no se puede hacer con java 11. en su lugar debe considerar la creación de un nuevo cargador de clases para que . Esto tiene la ventaja añadida de que usted será capaz de deshacerse de las nuevas clases, ya que no se cargan en el cargador de clases de la aplicación. También debe leer en capas - te dan una abstracción limpia para cargar un gráfico completamente nuevo módulo.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=188121&siteId=1
Recomendado
Clasificación