Feedback on open modules and packages

Scott Stark sstark at redhat.com
Wed Apr 12 18:46:04 UTC 2017


Relating to open modules and packages as defined in the current public review documents, we are seeing a lot of runtime errors when users begin a migration to using JMPS for their application when the modules they are interacting with make use of reflection. Two broad categories of this are frameworks like JavaFX which use reflection to determine which callback methods are implemented, and various data binding frameworks.


Creating a simple JavaFX application with the main class in a module requires the following to compile:
module jfxapp {
    requires javafx.graphics;
    requires javafx.controls;
}

However, this is not sufficient at runtime as the following exception is seen:
  
java -p out/production/Java9 -m jfxapp/org.jboss.fx.Appplication
Exception in Application constructor
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:563)
	at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:913)
Caused by: java.lang.RuntimeException: Unable to construct Application instance: class org.jboss.fx.Appplication
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:972)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:200)
	at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.IllegalAccessException: class com.sun.javafx.application.LauncherImpl (in module javafx.graphics) cannot access class org.jboss.fx.Appplication (in module jfxapp) because module jfxapp does not export org.jboss.fx to module javafx.graphics
	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:370)
	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:479)
	at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:884)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
	at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)

Process finished with exit code 1

To work around this the one has to either make the jfxapp module open or at a minimum, open the package which subclasses javafx.application.Application:

module jfxapp {
    requires javafx.graphics;
    requires javafx.controls;
    opens org.jboss.fx;
}


Cannot there be a syntax that the javafx.* module author uses to declare that read access will be required by any package that requires it so that this situation can be caught at compile time rather than having to fix access problems at runtime? What if there was a syntax along the lines of:

module javafx.graphics {
    exports javafx.pplication reflectively;
...
}

that allowed the compiler to verify that the jfxapp module was correctly configured to use the javafx.graphics module?

The issue is more difficult for automatic modules on the class path. A simple GSON binding application sees the same type of problem, but in this situation, the gson-2.8.0.jar has been promoted to a module by the Java runtime.


java -p /Users/starksm/Dev/Java/Java9/gson/target/classes:/Users/starksm/.m2/repository/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar -m org.jboss.gson/org.jboss.gson.Main
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make public org.jboss.gson.model.BagOfPrimitives() accessible: module org.jboss.gson does not "exports org.jboss.gson.model" to module gson
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281)
	at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:192)
	at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:185)
	at gson at 2.8.0/com.google.gson.internal.ConstructorConstructor.newDefaultConstructor(ConstructorConstructor.java:101)
	at gson at 2.8.0/com.google.gson.internal.ConstructorConstructor.get(ConstructorConstructor.java:83)
	at gson at 2.8.0/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:99)
	at gson at 2.8.0/com.google.gson.Gson.getAdapter(Gson.java:423)
	at gson at 2.8.0/com.google.gson.Gson.toJson(Gson.java:661)
	at gson at 2.8.0/com.google.gson.Gson.toJson(Gson.java:648)
	at gson at 2.8.0/com.google.gson.Gson.toJson(Gson.java:603)
	at gson at 2.8.0/com.google.gson.Gson.toJson(Gson.java:583)
	at org.jboss.gson/org.jboss.gson.Main.main(Main.java:13)

There is no module gson module author in this case, so it cannot be caught at compile time. Shouldn't this be handled at runtime as an implicit grant of readability from the org.jboss.gson.model package to the gson module due to the fact that the gson module was loaded automatically from the class path rather than the module path?


More information about the jpms-spec-comments mailing list