eclipse-efx / efxclipse-rt

Eclipse Public License 1.0
28 stars 29 forks source link

IllegalStateException in JavaModuleLayerModification #418

Open cdamus opened 3 years ago

cdamus commented 3 years ago

In my RCP application, I bundle a Java 11 VM with JavaFX 14. At run-time, I get a continual flood of exceptions (quoted below) from attempts by the JavaModuleLayerModification to modify the exports and opens of JavaFX bundles as specified by a few declarations in e(fx)eclipse bundle manifests. I don't need these, so it would be nice either to be able to easily turn off this functionality or else stem the flood of exceptions. The exception is thrown seemingly every time the class loader is asked for a class that isn't in the JRE because the FXClassLoader never completes its module modifications and so tries every time to do them, and fails.

I think the root cause of the problem is that the JavaFX modules that the e(fx)eclipse is trying to modify are discovered as already being in the base layer, as I have packaged them in my JRE. So, the assertion that they are in the layer created by the JavaModuleLayerModification fails. It is simply not possible for e(fx)eclipse to modify these modules using the JPMS API.

The work-around I am doing in my application for now is to exclude the org.eclipse.fx.osgi bundle from the package build because it only provides this class loader hook and I don't need that. However, this will be a problem when eventually the bundle gains more functionality.

So, perhaps this issue can be addressed for the general case by any combination of:


The exception:

FXClassLoader#collectModifications - Reads: []
FXClassLoader#collectModifications - Exports: [javafx.graphics/com.sun.javafx.scene=BUNDLE(@150), javafx.graphics/com.sun.javafx.application=BUNDLE(@164), javafx.graphics/com.sun.glass.ui=BUNDLE(@164)]
FXClassLoader#collectModifications - Opens: [javafx.graphics/javafx.scene=BUNDLE(@150)]
FXClassLoader#advancedModuleLayerBoostrap - Using advanced layer creation to apply patches
JavaModuleLayerModification#applyConfigurations - Exporting 'javafx.graphics/com.sun.javafx.scene=BUNDLE(@150)'
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at org.eclipse.fx.osgi.fxloader.jpms.ModuleLayerWrapper$ControllerWrapper.addExports(ModuleLayerWrapper.java:173)
    at org.eclipse.fx.osgi.fxloader.jpms.JavaModuleLayerModification.applyConfigurations(JavaModuleLayerModification.java:110)
    at org.eclipse.fx.osgi.fxloader.FXClassLoader.advancedModuleLayerBoostrap(FXClassLoader.java:483)
    at org.eclipse.fx.osgi.fxloader.FXClassLoader.initModuleLayer(FXClassLoader.java:426)
    at org.eclipse.fx.osgi.fxloader.FXClassLoader.getModuleLayer(FXClassLoader.java:293)
    at org.eclipse.fx.osgi.fxloader.FXClassLoader.findClassJavaFX11(FXClassLoader.java:207)
    at org.eclipse.fx.osgi.fxloader.FXClassLoader.postFindClass(FXClassLoader.java:144)
    at org.eclipse.osgi.internal.loader.BundleLoader.searchHooks(BundleLoader.java:530)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:493)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:425)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:171)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:398)
    at java.xml/javax.xml.parsers.FactoryFinder.getProviderClass(FactoryFinder.java:108)
    at java.xml/javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:183)
    at java.xml/javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:147)
    at java.xml/javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:271)
    at java.xml/javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:147)
    at org.eclipse.osgi.internal.framework.XMLParsingServiceFactory.createService(XMLParsingServiceFactory.java:59)
    at org.eclipse.osgi.internal.framework.XMLParsingServiceFactory.getService(XMLParsingServiceFactory.java:51)
    ...
Caused by: java.lang.IllegalArgumentException: module javafx.graphics not in layer
    at java.base/java.lang.ModuleLayer$Controller.ensureInLayer(ModuleLayer.java:216)
    at java.base/java.lang.ModuleLayer$Controller.addExports(ModuleLayer.java:268)
    ... 168 more
cdamus commented 3 years ago

Continuing to analyze my problem, I have learned that the Equinox Hook Registry supports a system property specifying hooks to exclude, so I can use that in my application to exclude the FXClassloaderHookConfigurator. That is better than leaving the org.eclipse.fx.osgi bundle out of my configuration (which was unpractical for a few reasons) and may obviate this issue. But perhaps the class loader hook may still internally improve its robustness and provide its own specific controls so that it may continue to provide other functionality and applications needn't exclude it altogether.

tomsontom commented 3 years ago

well the only purpose of the hooks in a Java-11 world is to spin up a new JPMS-Layer so that one can deploy JavaFX with the application. The first question is why is the org.eclipse.fx.osgi packaged at all?

We know which JPMS-Modules we've started up ourselves so we should be able to detect that we can't open up what we don't control.

cdamus commented 3 years ago

Thanks, Tom. This bundle is packaged because it's included in the org.eclipse.fx.target.rcp4.feature feature in which I get all the bits I need for my app. If there's a more appropriate feature to use, I could look at that, though it might complicate my software upgrade scenarios.

It wasn't clear to me from debugging this how it would be that a typical app deployment (mine may not be typical) is meant to instantiate JPMS modules in the OSGi context, especially when those modules are JavaFX. It sounds like you're suggesting a better way to avoid this exception than I've thought of so far, which is good.