Exception in Application start method (Simple Browser) [duplicate] - java

When I run my JavaFX 11 application with the following command:
/usr/lib/jvm/java-11-openjdk-amd64/bin/java
-p ~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11-linux.jar
--add-modules javafx.controls,javafx.graphics
-classpath ~/development/intellij/OpenPatrician/OpenPatricianStandalone/target/classes:
~/.OpenPatrician/plugins/maps/MinimalMap-Plugin.jar:
~/development/intellij/OpenPatrician/OpenPatricianDisplay/target/classes:
~/.m2/repository/ch/sahits/sahitsUtil/1.2.4/sahitsUtil-1.2.4.jar:
~/.m2/repository/junit/junit/4.12/junit-4.12.jar:
~/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:
~/.m2/repository/org/springframework/boot/spring-boot-starter-log4j2/2.1.0.RELEASE/spring-boot-starter-log4j2-2.1.0.RELEASE.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.11.1/log4j-slf4j-impl-2.11.1.jar:
~/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.1/log4j-api-2.11.1.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-core/2.11.1/log4j-core-2.11.1.jar:
~/.m2/repository/org/apache/logging/log4j/log4j-jul/2.11.1/log4j-jul-2.11.1.jar:
~/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:
~/.m2/repository/commons-cli/commons-cli/1.4/commons-cli-1.4.jar:
~/development/intellij/OpenPatrician/OpenPatricianImage/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianModel/target/classes:
~/development/intellij/OpenPatrician/GameEvent/target/classes:
~/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1.jar:
~/.m2/repository/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1.jar:
~/.m2/repository/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7.jar:
~/.m2/repository/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.jar:
~/.m2/repository/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15.jar:
~/.m2/repository/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11.jar:
~/.m2/repository/org/openjfx/javafx-swing/11/javafx-swing-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11.jar:
~/.m2/repository/org/openjfx/javafx-graphics/11/javafx-graphics-11-linux.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11.jar:
~/.m2/repository/org/openjfx/javafx-base/11/javafx-base-11-linux.jar:
~/development/intellij/OpenPatrician/OpenPatricianSound/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianUtilities/target/classes:
~/.m2/repository/org/springframework/spring-beans/5.1.2.RELEASE/spring-beans-5.1.2.RELEASE.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11.jar:
~/.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-linux.jar:
~/.m2/repository/commons-io/commons-io/2.6/commons-io-2.6.jar:
~/.m2/repository/com/thoughtworks/xstream/xstream/1.4.10/xstream-1.4.10.jar:
~/.m2/repository/xmlpull/xmlpull/1.1.3.1/xmlpull-1.1.3.1.jar:
~/.m2/repository/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar:
~/.m2/repository/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar:
~/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11.jar:
~/.m2/repository/org/openjfx/javafx-media/11/javafx-media-11-linux.jar:
~/.m2/repository/org/springframework/spring-context/5.1.2.RELEASE/spring-context-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-aop/5.1.2.RELEASE/spring-aop-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-expression/5.1.2.RELEASE/spring-expression-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-oxm/5.1.2.RELEASE/spring-oxm-5.1.2.RELEASE.jar:
~/.m2/repository/com/google/guava/guava/24.1-jre/guava-24.1-jre.jar:
~/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar:
~/.m2/repository/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0.jar:
~/.m2/repository/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar:
~/.m2/repository/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar:
~/.m2/repository/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar:
~/development/intellij/OpenPatrician/OpenPatricianJavaFX/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianGameEvent/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianClientServerInterface/target/classes:
~/.m2/repository/org/springframework/boot/spring-boot-starter-aop/2.1.0.RELEASE/spring-boot-starter-aop-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.0.RELEASE/spring-boot-starter-2.1.0.RELEASE.jar:
~/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:
~/.m2/repository/org/aspectj/aspectjweaver/1.9.2/aspectjweaver-1.9.2.jar:
~/development/intellij/OpenPatrician/OpenPatricianServer/target/classes:
~/development/intellij/OpenPatrician/OpenPatricianEngine/target/classes:
~/.m2/repository/com/carrotsearch/hppc/0.7.2/hppc-0.7.2.jar:
~/.m2/repository/org/springframework/spring-core/5.1.2.RELEASE/spring-core-5.1.2.RELEASE.jar:
~/.m2/repository/org/springframework/spring-jcl/5.1.2.RELEASE/spring-jcl-5.1.2.RELEASE.jar:
~/.m2/repository/org/reflections/reflections/0.9.11/reflections-0.9.11.jar:
~/.m2/repository/org/javassist/javassist/3.21.0-GA/javassist-3.21.0-GA.jar:
~/development/intellij/OpenPatrician/OpenPatricianData/target/classes:
~/.m2/repository/org/projectlombok/lombok/1.18.2/lombok-1.18.2.jar:
~/.m2/repository/org/springframework/boot/spring-boot-devtools/2.1.0.RELEASE/spring-boot-devtools-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot/2.1.0.RELEASE/spring-boot-2.1.0.RELEASE.jar:
~/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.0.RELEASE/spring-boot-autoconfigure-2.1.0.RELEASE.jar
ch.sahits.game.openpatrician.standalone.OpenPatricianApplication
I run into this error:
Exception in thread "JavaFX Application Thread" java.lang.IllegalAccessError: class com.sun.media.jfxmediaimpl.NativeMediaManager (in unnamed module #0x4d7be377) cannot access class com.sun.glass.utils.NativeLibLoader (in module javafx.graphics) because module javafx.graphics does not export com.sun.glass.utils to unnamed module #0x4d7be377
at com.sun.media.jfxmediaimpl.NativeMediaManager.lambda$new$0(NativeMediaManager.java:136)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.media.jfxmediaimpl.NativeMediaManager.<init>(NativeMediaManager.java:107)
at com.sun.media.jfxmediaimpl.NativeMediaManager$NativeMediaManagerInitializer.<clinit>(NativeMediaManager.java:78)
at com.sun.media.jfxmediaimpl.NativeMediaManager.getDefaultInstance(NativeMediaManager.java:90)
at com.sun.media.jfxmedia.MediaManager.canPlayProtocol(MediaManager.java:78)
at com.sun.media.jfxmedia.locator.Locator.<init>(Locator.java:239)
at com.sun.media.jfxmediaimpl.NativeMediaAudioClip.<init>(NativeMediaAudioClip.java:53)
at com.sun.media.jfxmediaimpl.NativeMediaAudioClip.load(NativeMediaAudioClip.java:63)
at com.sun.media.jfxmediaimpl.AudioClipProvider.load(AudioClipProvider.java:66)
at com.sun.media.jfxmedia.AudioClip.load(AudioClip.java:135)
at javafx.scene.media.AudioClip.<init>(AudioClip.java:83)
at ch.sahits.game.openpatrician.sound.impl.LoopTrack.lambda$new$0(LoopTrack.java:26)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
at java.base/java.lang.Thread.run(Thread.java:834)
As I understand this exception there is something wrong with my module setup, but I am not clear what I need to change:
Add additional modules to --add-modules and which?
Add --add-opens to the command with which modules
Something completely different?

TL;DR: You need to make sure javafx.media is resolved as a module from the module-path. You can do this by either:
Including it in the VM arguments: --add-modules javafx.controls,javafx.media
Or making your own code modular, adding an appropriate requires javafx.media; directive to your module descriptor, and using --module to launch your application.
If you're not sure how or where to set the VM arguments in your IDE and/or build tool, check out Getting Started with JavaFX.
The Problem
The error is related to the Java Platform Module System, added in Java 9. If you're not aware of what modules are and how they work, check out this blog: Understanding Java 9 Modules. Here's a small excerpt:
Modularity adds a higher level of aggregation above packages. The key new language element is the module—a uniquely named, reusable group of related packages, as well as resources (such as images and XML files) and a module descriptor specifying
the module’s name
the module’s dependencies (that is, other modules this module depends on)
the packages it explicitly makes available to other modules (all other packages in the module are implicitly unavailable to other modules)
the services it offers
the services it consumes
to what other modules it allows reflection
With the introduction of modules, JavaFX was also modularized. It is now made up of seven modules, as can be seen by its Javadoc. These modules share some of their internals between themselves, but not with application developers. This is accomplished through qualified exports/opens directives.
Your Error
This is your error:
java.lang.IllegalAccessError: class com.sun.media.jfxmediaimpl.NativeMediaManager (in unnamed module #0x4d7be377) cannot access class com.sun.glass.utils.NativeLibLoader (in module javafx.graphics) because module javafx.graphics does not export com.sun.glass.utils to unnamed module #0x4d7be377
It's telling you a class in the unnamed module is attempting to access a class in a different, named module: javafx.graphics. However, the latter module does not export the needed package to at least the unnamed module. Looking at the error message and the given class names, we can deduce that the class in the unnamed module is part of JavaFX's media implementation. This suggests the class should be in the javafx.media module. Then why does the error mention the unnamed module?
The unnamed module is the module all classes on the class-path belong to. What this means is that the javafx.media module was put on the class-path and lost its identity. A consequence of this is that all the qualified exports/opens directives declared by the javafx.graphics module which grant the javafx.media module the necessary access no longer apply—hence the IllegalAccessError.
But... You Used the Module-Path
From the command line you provided in your question we can see the javafx-media-11.jar file was placed on the module-path (-p). So what is the problem? The problem is caused by placing the media JAR file on both the module-path and the class-path, while simultaneously failing to ensure the javafx.media module is resolved as a module.
The algorithm for module resolution is described by the java.lang.module package documentation. Basically, it starts with a set of root modules and then recursively enumerates the requires directives. The root modules are determined by the --add-modules and --module arguments. Your code isn't modular, meaning you don't use --module, and you have:
--add-modules javafx.controls,javafx.graphics
In other words, none of the root modules directly or indirectly require the javafx.media module, thus it is never resolved. Since the classes are also on the class-path they're still found, but now in the unnamed module. If you had not placed the JavaFX dependencies on the class-path as well then you'd be getting a ClassNotFoundException.
The Solution
The solution is simple: Make sure the javafx.media module is resolved. There are at least two ways to accomplish this:
Include the module in your --add-modules argument.
--add-modules javafx.controls,javafx.media
Note you don't need to specify the javafx.graphics module as it'll be pulled in implicitly by the other modules; both javafx.controls and javafx.media require javafx.graphics. The same general reasoning also applies to the javafx.base module in this case.
The Getting Started with JavaFX guides show how to configure the VM options for JavaFX in each of the major IDEs (i.e. IntelliJ, Eclipse, and NetBeans) and build tools (i.e. Maven and Gradle).
Make your own code modular and add the necessary requires directives.
module app {
requires javafx.controls;
requires javafx.media;
// replace with your Application class' package
exports com.example.app to javafx.graphics;
}
Then make sure to launch your application with --module.
Notice the qualified exports to javafx.graphics. This is required in order for JavaFX to reflectively instantiate your application class. There are similar requirements (qualified opens) for FXML controllers and other APIs which require private reflective access.
There is another option: Place everything on the class-path, including the JavaFX modules, and ignore JPMS modules completely. If you do this your main-class must not be a subclass of Application. You'd have to create a separate launcher class that simply launches JavaFX. Warning: This approach is not supported.
If you use Maven, you can see how to rely on the JavaFX media module here as a dependency here:
JavaFX media player import (Maven)

If you're using VSCode, here's a simple solution to your problem:
In the java proyect exist a folder called .vscode, inside this exist a .json file called launch.json.
directory: Image
launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch Main",
"request": "launch",
"vmArgs": "--module-path /Users/ASUS/javafx-sdk-16/lib --add-modules javafx.controls,javafx.fxml",
"mainClass": "main.java.Main",
"projectName": "MorseJavaFx_41229da3"
},
{
"type": "java",
"name": "Launch Current File",
"request": "launch",
"mainClass": "${file}"
}
]
}
So, in the line "vmArgs", you must add javafx.media to the final and inside the quotes, like this:
"vmArgs": "--module-path /Users/ASUS/javafx-sdk-16/lib --add-modules javafx.controls,javafx.fxml, javafx.media"
Enjoy.😄

Related

JavaFX with Gradle error module not found

I'm creating a sample demo application with JavaFX in IntelliJ, but I need to use a library called the JavaFaker library. I'm using Gradle as the build system, but every time I try to add the library, either as the implementation in the build.gradle file, or via IntelliJ project structure options, the module.java file says error: module not found. I've already tried adding it to modules but nothing changes.
module-info.java
module com.example.demo1 {
requires javafx.controls;
requires javafx.fxml;
requires javafaker;
opens com.example.demo1 to javafx.fxml;
exports com.example.demo1;
}
build.gradle
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.24.1'
}
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.8.2'
javaFakerVersion = '1.0.2'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'com.example.demo1'
mainClass = 'com.example.demo1.HelloApplication'
}
javafx {
version = '17.0.1'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
implementation("com.github.javafaker:javafaker:${javaFakerVersion}")
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip") as RegularFile
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}
error message
> Task :HelloApplication.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafaker not found, required by com.example.demo1
I tried for a while to get this to work with Gradle but was unable to. I don't know Gradle well, but unless you do, I don't advise trying it.
Alternate option: use a static import
I didn't try this, but this is suggested in another answer.
Before you try this, see:
What's the difference between requires and requires static in module declaration
It is IMO, a bit of a hack in this usage case. This makes the module optional at runtime. But, if the module is on the classpath instead of the module path its code can still be used. More information quoted from the linked answer:
A requires static clause expresses a dependency that is optional at
run time. That means at compile time the module system behaves exactly
as described above.
At run time, on the other hand, it mostly ignores requires static
clauses. If it encounters one, it does not resolve it. That means, if
an observable module is only referenced with requires static, it does
not make it into the module graph!
Alternate option: Non-modular project
You can fix this issue by making your project non-modular:
Delete your module-info.java file.
Run your application with JavaFX modules on the module-path.
The org.openjfx.javafxplugin you are already doing will help achieve this by specifying the modules to be used.
To execute the application directly in the IDE rather than through Gradle, you will need to specify the module options to the VM for the IDE execution configuration (information on that is in the getting started documentation at openjfx.io).
For packaging, switch to using the badass-runtime-plugin rather than the badass-jlink-plugin. This will package the application via jpackage rather than jlink (which cannot package non-modular applications or applications with automatic modules).
In the application block of your build file, you no longer need to specify the module for your application as you no longer have one.
While that means that your application is no longer modular, in this case, in my opinion, this is not such a big loss. The dependencies you are using are not well-defined modules, so you can't use jlink to create a package for your application, and you don't have the level of modular encapsulation and definition you would normally receive for fully modular projects.
For more information, see the Getting started instructions at:
https://openjfx.io/openjfx-docs/
Under the sections "Non-Modular with Gradle" for your selected IDE.
Alternate option: Using Maven
It is easy to get this to work with Maven.
Create a new JavaFX project
Choose Maven as your build system instead of Gradle.
Add the javafaker dependency to your pom.xml.
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
Press the refresh icon in the Maven window to reimport the Maven project into the IDE.
Add the requires clause for the javafaker module into your module-info.java
requires javafaker;
Add the code to use javafaker to your app.
I don't have code to use javafaker, so I could not verify that the last step would work, but, give it a try . . .
Why you can receive this issue when using Gradle, but not Maven
Looking at the Gradle Documentation section "Using libraries that are not modules":
A third case are traditional libraries that provide no module information at all — for example commons-cli:commons-cli:1.4. Gradle puts such libraries on the classpath instead of the module path. The classpath is then treated as one module (the so called unnamed module) by Java.
This is the case with the javafaker dependency that you are using. It has no module-info.java and does not define the property Automatic-Module-Name in its manifest file (which are the other two cases in the section). Both the other cases result in Gradle putting the library on the module path, but the case you have means that it is on the class path.
This is a problem when you want to access the code from a named module that you define, which you have because you created a module-info.java.
Your module can only find code and resources of modules it requires (which need to be on the module path), so you add requires javafaker to the module-info.java, and get the following when you try to run through the IDE:
java.lang.module.FindException: Module javafaker not found, required by com.example.demo1
So you remove the requires javafaker from the module-info.java as advised by the Gradle documentation I linked and you get the following when you try to compile:
Package 'com.github.javafaker' is declared in module 'javafaker', but module 'com.example.demo1' does not read it
So you must place the library in the module-info to use it, but you can't place the library in module-info because Gradle puts in on the classpath -> catch-22.
There are workarounds to this such as providing VM arguments to allow access to the unnamed module (which is the classpath), or maybe modifying the module path handling of the Gradle build and/or IDE somehow (I don't know how), but they are pretty ugly.
On the other hand, for this case, Maven acts differently from Gradle, it places the dependent library on the module path, even if it does not have a module-info.java or Automatic-Module-Name defined. This means that it was (for me) much easier to set up and use.
Incidental advice on module naming
This is not an error, but note: Although module names with numbers in them are now allowed due to a change in the module system specification, it is probably best not to put numbers in module names to prevent the module name and version info being confused.
I've had a similar issue recently. Adding static to the requires statement helped however. Maybe this will fix your issue without having to switch to maven.
So you'd need to add: requires static javafaker;

Are there any JDK 11+ system modules which are not root modules?

In JDKs 9 and 10, there used to be a few modules such as java.xml.bind, containing Java EE classes. They were marked as deprecated and to be removed with the advent of JDK 9 and finally removed in 11 (see JEP 320). In a product I am contributing to, there used to be tests for the javac compiler option --add-modules, adding those modules as root modules. Those tests have been deactivated for JDK 11+. Instead of removing them, I would like to reactivate them, if there are any other JDK modules which are also non-root by default. The tests could then just use those modules instead.
I know I can just test --add-modules with my own modules, but then I have to specify them on the module path. The test case that an extra module path is not necessary for JDK modules added via --add-modules is also interesting, if any JDK 11+ modules still exist to be tested against. I am not talking about non-exported packages, but really about non-root JDK modules.
So, according to the information in this answer, I am actually looking for non-java.* modules among the system modules which do not export at least one package without qualification. In that case, those modules should not be root, and they would be eligible for my test case.
Update: What I am looking for is an equivalent for this in JDK 9:
import javax.xml.bind.JAXBContext;
public class UsesJAXB {
JAXBContext context;
}
xx> "C:\Program Files\Java\jdk-9.0.4\bin"\javac UsesJAXB.java
UsesJAXB.java:1: error: package javax.xml.bind is not visible
import javax.xml.bind.JAXBContext;
^
(package javax.xml.bind is declared in module java.xml.bind, which is not in the module graph)
1 error
xx> "C:\Program Files\Java\jdk-9.0.4\bin"\javac --add-modules java.xml.bind UsesJAXB.java
See? With --add-modules it builds, without it does not.
I am looking for modules (if any) in JDK 11-18, which would yield the same result when importing their classes in a simple program, i.e. require them to be explicitly added via --add-modules for compilation (not talking about runtime).
You can list all modules of the jdk with:
java --list-modules
Then you can print the module descriptors with:
java --describe-module a.module.name
After filterting these outputs in a little script, here are the modules of my JDK 17 than could qualify:
jdk.charsets
jdk.crypto.cryptoki
jdk.crypto.ec
jdk.editpad
jdk.internal.vm.compiler
jdk.internal.vm.compiler.management
jdk.jcmd
jdk.jdwp.agent
jdk.jlink
jdk.jpackage
jdk.localedata
jdk.zipfs
jdk.charsets, for instance, is a module providing a service.
Update after question update
So you are looking for a module that exports a package but is not in the default module graph when compiling a class in the unnamed module. According to the JEP, only java.* modules can qualify.
When I'm looking for modules required, either directly or indirectly, by java.se (which is a root module when it exists), I see all java.* modules of the JDK, but java.smartcardio. And due to some unknown magic, java.smartcardio is also in the default graph : I tried to compile a class importing one of its class and it works without --add-modules.
So I think you are down to using a non-java module exporting no package (like jdk.charsets), importing one of its class (like sun.nio.cs.ext.ExtendedCharsets) and either:
add --add-exports in addition to --add-modules when compiling your test class so that javac succeeds.
or parse the error message of javac and distinguish between "not in the module graph" and "not exported".

Calling a Non Module Class from a Module Class in java 9

I am trying to call a non-module class from a module class. I have created a folder structure
moduledemo > allclasses > moduleC > packageC > MyMethods.class
is the path to my module class file
moduledemo > moduleC > packageC > MyMethods.java
and
moduledemo > nomodule > packageD > DemoNoModule.class
is the no module class that I am calling from MyMethods.java
I am able to compile the DemoNoModule file. I am able to compile MyMethods.java into allclasses folder moduleC.
When I am running MyMethods I am getting error moduleC not found. Can anyone update? I am using the following command to run
java --module-path allclasses -m moduleC/packageC.MyMethods
Both files code -> Non-Module Class
package packageD;
public class DemoNoModule {
public void showD() {
System.out.println("this is show of D in No Module");
}
}
Module class calling class
package packageC;
import packageD.*;
public class MyMethods {
public static void main(String s[]) {
DemoNoModule d=new DemoNoModule();
d.showD();
}
}
Module info in module C
module moduleC {
exports packageC;
}
On one hand, the moduleC(mind improving naming?) is a named module.
While on another, the "no module class" termed by you is nothing but as stated by Alan a class present on the classpath. The classes present on the classpath during the execution are part of an unnamed module in JPMS.
Quoting the documentation further:-
The unnamed module exports all of its packages. This enables
flexible migration... It does not, however, mean
that code in a named module can access types in the unnamed module. A
named module cannot, in fact, even declare a dependence upon the
unnamed module.
This is intentional to preserve the reliable configuration in the module system. As stated further :
If a package is defined in both a named module and the unnamed module
then the package in the unnamed module is ignored. This preserves
reliable configuration even in the face of the chaos of the class
path, ensuring that every module still reads at most one module
defining a given package.
Still, to make use of a class from the unnamed module in your named module moduleC, you can follow the suggestion of making use of the flag to add ALL-UNNAMED module to be read by modules on the module path using the
following command:
--add-reads <source-module>=<target-module> // moduleC=ALL-UNNAMED
As a special case, if the <target-module> is ALL-UNNAMED then
readability edges will be added from the source module to all present
and future unnamed modules, including that corresponding to the class
path.
PS: Do take into consideration the highlighted portion(above) of the documentation as you do so.
Also note the long-term solution would be to revise your design here, for which you can plan to move your code in the class DemoNoModule into an explicit module or package it separately to be converted into an automatic module.
Java 9 programs are supposed to be modular. That is how I understood jigsaw in JDK-9. So, IMHO, you'll have to 'wrap' your packageD in another module and in the module-info for moduleC write requires moduleD. Also moduleD should export packageD.
ALL-UNNAMED is added for backward compatibility, and I suppose it will be removed in some point of Java evolution.

Unnamed module interaction with named module by ServiceLoader::load

I have a project like this:
\---main
\---src
\---com.foo
\---UnnamedStart.java
\---api
\---src
\---com.foo.api
\---ApiInterface.java
\---module-info.java
\---impl
\---src
\---com.foo.impl
\---ApiInterfaceImpl.java
\---module-info.java
Implementatio of UnnamedStart.java is:
public static void main(String[] args) {
ServiceLoader<ApiInterface> services = ServiceLoader.load(ApiInterface.class);
...
}
Note that main is unnamed module.
api/src/module-info.java is:
module com.foo.api {
exports com.foo.api;
}
and impl/src/module-info.java is:
update 1.1 - code below updated see comments, added requires
update 1.2 - code below updated, provides A with B changed to provides B with A mistake during creating question, originally was ok
module com.foo.impl {
requires com.foo.api; //added (update 1.1)
provides com.foo.impl.ApiInterface
with com.foo.api.ApiInterfaceImpl; //vice versa (update 1.2)
}
When I run my code in UnnamedStart.java I end up with no element in services.
I also tried to create a static method in com.foo.api.ApiInterface:
static List<ApiInterface> getInstances() {
ServiceLoader<ApiInterface> services = ServiceLoader.load(ApiInterface.class);
List<ApiInterface> list = new ArrayList<>();
services.iterator().forEachRemaining(list::add);
return list;
}
and add in api/src/module-info.java line uses com.foo.api.ApiInterface; but it gave the same result (nothing).
The only way I made it work is by migrating main from unnamed to named module.
1. How does java 9 work when unnamed module trying to interact with named module?
2. Does it possible to make it work and keeping the main like unnamed module?
update 1.3 - added related project
ServiceLoader::load works as usual, but the are other things.
[Short answer]
1. Unnamed module reads the same like named module to named module, but named module can not access types in the unnamed module.
2. You are trying to launch an application from a non-modular JAR so you have to explicitly resolve required modules by --add-modules com.foo.impl.
Note that your required modules have to be on module graph (e.g. add by --module-path).
[More details]
1. There are 4 different types of modules: built-in platform module, named module, automatic module, unnamed module and each of them are named apart from unnamed module
As they wrote the unnamed module treats all the other modules the same like named module:
All other modules have names, of course, so we will henceforth refer to those as named modules.
The unnamed module reads every other module. [...]
The unnamed module exports all of its packages. [...] It does not, however, mean that code in a named module can access types in the unnamed module. A named module cannot, in fact, even declare a dependence upon the unnamed module.
[...]
If a package is defined in both a named module and the unnamed module then the package in the unnamed module is ignored.
Even an automatic module indeed is also named:
An automatic module is a named module that is defined implicitly, since it does not have a module declaration.
2. Second part of this answer
If you compile non-modular code or launch an application from a non-modular JAR, the module system is still in play and because non-modular code does not express any dependencies, it will not resolve modules from the module path.
So if non-modular code depends on artifacts on the module path, you need to add them manually with the --add-modules option. Not necessarily all of them, just those that you directly depend on (the module system will pull in transitive dependencies) - or you can use ALL-MODULE-PATH (check the linked post, it explains this in more detail).
This #nullpointer comment will be useful
Also, the module resolution still needed the impl to be resolved during the startup. To check which you could also make use of the --show-module-resolution flag.

Method getModule returning unnamed module for class in named module

I just started to have a look at the Java 9 module system and I was wondering whether it is possible for a class to know in which module it is located.
Therefor I created the following module
module de.test {
exports de.test.myexport;
}
and compiled a jar file that looks like
> jar --print-module-descriptor --file=Java9Test-1.0-SNAPSHOT.jar
de.test
requires mandated java.base
exports de.test.myexport
In package de.test, I have a class called Overview where I'm calling
Module module = Overview.class.getModule();
However, the returned module object is unnamed and has no ModuleDescriptor.
Am I using getModule() correctly here, or is there any other way to load the module of a class?
I'm using JDK 9 build 120 on OS X.
All JARs on the class path (with java --class-path ...) get bundled into the same so-called unnamed module, regardless of whether they are "a real module" or "just a JAR". When you ask a class from such a JAR for its module, you get the result you describe.
Try putting the JAR on the module path (with java --module-path ...) and Class::getModule should return what you expect.

Categories

Resources