Let's assume an OpenJDK 11 + OpenJFX 11 based application. The codebase is organized in a single java module (see A Guide to Java 9 Modularity for reference).
Until now I combined all my JavaFX based projects with Google's dependency injection framework Guice. For modular projects, this doesn't seem to work...
SQLiteCompassApplication.java
public class SQLiteCompassApplication extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) throws Exception {
Injector injector = Guice.createInjector(new MyModule());
FXMLLoader fxmlLoader = injector.getInstance(FXMLLoader.class);
try(InputStream fxmlStream = getClass().getResourceAsStream("/view/View.fxml")) {
Parent root = fxmlLoader.load(fxmlStream);
stage.setScene(new Scene(root));
stage.setTitle("SQLite Compass");
stage.setOnCloseRequest(event -> System.exit(0));
stage.show();
}
}
}
module-info.java
module org.x1c1b.sqlitecompass {
requires javafx.controls;
requires javafx.fxml;
requires com.google.guice;
exports org.x1c1b.sqlitecompass;
}
To keep it simple the Guice configuration, which means the declared Guice modules (not to confuse with java modules), isn't pasted but still working for non-modular projects.
When executing this code I receive the following exception:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field com.google.inject.Injector org.x1c1b.sqlitecompass.config.provider.FXMLLoaderProvider.injector accessible: module org.x1c1b.sqlitecompass does not "opens org.x1c1b.sqlitecompass.config.provider" to module com.google.guice
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:170)
at com.google.guice@4.2.2/com.google.inject.internal.SingleFieldInjector.<init>(SingleFieldInjector.java:38)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.getInjectors(MembersInjectorStore.java:126)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.createWithListeners(MembersInjectorStore.java:93)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore.access$000(MembersInjectorStore.java:36)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore$1.create(MembersInjectorStore.java:45)
at com.google.guice@4.2.2/com.google.inject.internal.MembersInjectorStore$1.create(MembersInjectorStore.java:41)
at com.google.guice@4.2.2/com.google.inject.internal.FailableCache$1.load(FailableCache.java:40)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3444)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2193)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2152)
at com.google.common@25.1-android/com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2042)
... 39 more
Exception running application org.x1c1b.sqlitecompass.SQLiteCompassApplication
I could fix this issue by pasting opens org.x1c1b.sqlitecompass.config.provider;
to module-info.java
. But this results in further exceptions...
How should I configure my module/module-info.java
to use it with Google Guice in general? Is it possible to use Google Guice and Modularity in combination?
EDIT
It seems to work when I change the following lines:
- Add
exports org.x1c1b.sqlitecompass.config
, where my Guice modules are declared, tomodule-info.java
- Execute the program with the additional VM option
--add-opens java.base/java.lang=com.google.guice
But I would guess it's more a workaround found here than an official solution...