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:
exports org.x1c1b.sqlitecompass.config
, where my Guice modules are declared, to module-info.java
--add-opens java.base/java.lang=com.google.guice
But I would guess it's more a workaround found here than an official solution...
You have to open all your packages which will be accessed via reflection by Guice.
The easiest way to do that is to just declare your whole module as open
by putting this word in front of module
in your module-info.java
.