I'm getting following issues with Jlink -
Error: automatic module cannot be used with jlink
Error: Modules aws.java.sdk.s3 and aws.java.sdk.core export package com.amazonaws.auth to module listenablefuture
I have tried creating a module-info.java with jdeps or using plugins like moditect to generate module-info for the module and inject it in existing JAR. Didn't work.
Is there any other way to create a JRE that includes automatic modules.
Related
I have a JavaFX application that works as expected. I need to use Apache POI to read and write excel files. The following are the steps I have taken:
Added the required dependency
implementation 'org.apache.poi:poi-ooxml:5.2.3'
Added the module to module-info.java
requires org.apache.poi.ooxml;
Tried to use the library within a function:
#FXML
private void downloadTemplate() {
XSSFWorkbook workbook = new XSSFWorkbook();
}
All this is fine with no issues. However when I try to run the application, I get the following two errors (interchanging)
> Task :Start.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module SparseBitSet not found, required by org.apache.poi.ooxml
and
> Task :Start.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module commons.math3 not found, required by org.apache.poi.ooxml
I can however, clearly see both libraries under 'external libraries'
I am using IntelliJ Community Edition 2022.1.2 and running the project using Java 17.0.1. Any help would be highly appreciated.
SparseBitSet is an automatic module, it has no module-info of its own (probably commons-math3 is as well), and is without an Automatic-Module-Name entry in its manifest.
Gradle puts libraries without a module-info.class or an Automatic-Module-Name in their manifest on the class path, not the module path, so they won't be treated as modules, and the module finder won't find them.
You can:
hack the gradle build to allow the modules to be found. (I don't use Gradle so I have no specific advice on how to do that other than referring to the documentation).
Hack the library jar which you want to be treated as a module to include a module-info.class or an Automatic-Module-Name in its manifest.
Or, switch to maven, which automatically places automatic modules on the module path.
The easiest way to do this, IMO, is to create a new JavaFX project in Idea, then add the required dependencies as maven dependencies and add your code.
Or, as swpalmer suggests in the comments, request that library maintainers update their codebase to make their libraries modular.
And, when you run your app, make sure all jars are on the module path, not the class path.
Or, make your app non-modular by removing the module-info.java from it, then manually place the JavaFX modules on the module-path and add them with the --add-modules switch.
FAQ
Are you SURE that automatic modules are put on the class path by Gradle?
From the Gradle documentation section Building Modules for the Java Module System:
To tell the Java compiler that a Jar is a module, as opposed to a
traditional Java library, Gradle needs to place it on the so called
module path. It is an alternative to the classpath, which is the
traditional way to tell the compiler about compiled dependencies.
Gradle will automatically put a Jar of your dependencies on the module
path, instead of the classpath, if these three things are true:
java.modularity.inferModulePath is not turned off
We are actually building a module (as opposed to a traditional
library) which we expressed by adding the module-info.java file.
(Another option is to add the Automatic-Module-Name Jar manifest
attribute as described further down.)
The Jar our module depends on is itself a module, which Gradles
decides based on the presence of a module-info.class — the compiled
version of the module descriptor — in the Jar. (Or, alternatively, the
presence of an Automatic-Module-Name attribute the Jar manifest)
It is the third point that is key. Java can treat a library with no module-info.class and no Automatic-Module-Name in the Jar manifest as an automatic module if it is on the module path. However, Gradle will by default, only place libraries which fulfill one of those two conditions on the module path.
Using jewelsea's answer above, I have been able to solve the problem. I am posting the answer here to help anyone else who encounters the problem in future.
So, the overall problem is, as said in the answer above, both SparseBitSet and commons-math3 are automatic modules with no module-info of their own. The solution that worked for me was to convert them into the modules expected by the project. Here are the steps I took:
Use a gradle plugin 'extra-java-module-info'. The github page didn't show how to import it to a normal gradle file so here it is:
plugins {
id 'org.gradlex.extra-java-module-info' version '1.0'
}
Note the names that your application expects for the modules. In my case, from the error messages thrown, they were 'SparseBitSet' and 'commons-math3'
Locate the said libraries on the sidebar under 'external libraries' and note the 'jar' file names. In my case, they were 'commons-math3-3.6.1.jar' and 'SparseBitSet-1.2.jar'.
Add a section 'extraJavaModuleInfo' to your gradle files and use the parameters as follows: module('jar file name', 'name expected by your project', 'jar version'), as shown in the blue rectangle in the image above.
extraJavaModuleInfo {
module('commons-math3-3.6.1.jar', 'commons.math3', '3.6.1')
module('SparseBitSet-1.2.jar', 'SparseBitSet', '1.2')
}
That's it. Try to sync and run your project. Thanks jewelsea.
Hello I have a problem with my modular Java FX Application.
First of all I created a JavaFX Project with the Intellij Wizard.
I added the Java FX lib:enter image description here
I also added the VM options:enter image description here
But I always get this errormessage:enter image description here
"Error occurred during initialization of boot layer
java.lang.module.FindException: Module com.example.hudrava_test not found
"
Thank you.
Steps to address your issue
Ensure that you are using the most recent stable version of Idea (currently 2021.3.2), Java and JavaFX (currently 17.0.2).
Discard your current project.
Create a new project.
Follow the instructions at Create a new JavaFX project provided by Idea on how to use their wizard.
If you follow the instructions exactly it should work.
You don't need to add "the Java FX lib" to the project manually.
The wizard will create a dependency in Maven or Gradle which includes the most common JavaFX modules.
You don't need to download or use the JavaFX SDK mentioned at openjfx.io.
You don't need to explicitly set any VM arguments such as --add-modules the wizard will create the a module-info.java file which references the modules.
Before proceeding any further, make sure that the basic generated project build and runs in your environment (according to the build and execution instructions documented by IntelliJ for the new JavaFX project wizard).
Using additional JavaFX modules
If you want to use additional JavaFX modules (e.g. javafx.media or javafx.web):
Add the additional modules manually to the maven or gradle build file.
Reimport the build file into the Idea project.
Add requires clauses form the modules to the module-info.java.
Making your application non-modular
Even if your application is made non-modular, you still need to have JavaFX modules on the module path as that is the only way the execution of JavaFX is supported.
If you don't want a modular application, you can delete the module-info.java file and manually add VM arguments for the module path to the JavaFX and an --add-modules switch.
I do not advise doing this step unless:
You have a good reason not to have a non-modular application (e.g. rely on 3rd party dependencies which do not integrate easily with the Java module system), AND
You have knowledge about how to make non-modular JavaFX applications.
Cause of the module find exception
The reason for your specific error:
java.lang.module.FindException: Module com.example.hudrava_test not found
is because you don't have module-info.java for a module with that name on the module path. Note that is not a JavaFX module name, but something you have specified. You have tried to run the application by specifying a class name within the non-existent module, e.g.
java --module-path <somepath> -m com.example.hudrava_test/com.example.hudrava_test.HelloApplication
You can find out further info about that in:
java.lang.module.FindException: Module not found.
However, you should not need to manually take the steps outlined in that answer, because, when you create a new project using the new JavaFX wizard, it will automatically create a module-info.java file and place your application's build output on the modulepath.
So the error was caused by something you did after creating the project with the wizard (I don't know what). When you create a new project, you should not have the error.
On module naming and underscores
The Jenkov module tutorial states:
A Java module name follows the same naming rules as Java packages. However, you should not use underscores (_) in module names (or package names, class names, method names, variable names etc.) from Java 9 and forward, because Java wants to use underscore as a reserved identifier in the future.
It is recommended to name a Java module the same as the name of the root Java package contained in the module - if that is possible (some modules might contain multiple root packages).
So, it is inadvisable to have underscores in either your module or your package name.
More info on module naming suggestions is provided in:
How should I name my Java 9 module?
I am currently in the process of trying to deploy my JavaFX application (either with a jar or an installer, however an installer would be preferred). I have seen some sources point to using jlink, in which I have tried to no avail.
While I would have no problem building normally with jlink, I am trying to include a custom serialization utility I made with Maven and Java 17 (no JavaFX, but it is a single modular with a module-info). To import this into my project, I am simply adding it as a dependency. Additionally, this dependency requires SnakeYAML, which I don't believe is a modular project? (Important later)
Now, with this dependency, if I try to run javafx:jlink, I typically get an error like "jlink does not work with automatic modules" (in reference to my serialization utility).
My setup:
JavaFX 17.0.1
JDK 17.0.1
Maven 3.8.4
IntelliJ IDEA ultimate
So, my main two questions:
Should I even bother with jlink, especially if I am trying to get an installer?
With modular projects like my JavaFX project, how do I add dependencies from other modular projects (and also, within the serialization utlity, somehow shade SnakeYAML) and allow them to be compiled with JavaFX?
Should I even bother with jlink, especially if I am trying to get an installer?
No.
You can make use of jlink during the process, but, in my experience, it is not necessary. Also, the images jlink creates can be a little difficult to integrate with what is required by jpackage, which you will need to use anyway.
Instead, use jpackage, not jlink if you want an installer.
jpackage can both link your application and create an installer, but jlink can only link and cannot create an installer.
With modular projects like my JavaFX project, how do I add dependencies from other modular projects (and also, within the serialization utlity, somehow shade SnakeYAML) and allow them to be compiled with JavaFX?
Don’t shade jars when packaging, it is not necessary. Also, if the jars are modular, it will break their modularity and they might not work (for example the JavaFX jars are not supported when shaded into a jar).
To add compile dependencies, you are already using Maven, just use its compile dependency mechanism.
For jar dependencies which you have created yourself, use the Maven install command to install the dependencies into your local repository, or use the install facilities in your repository manager (e.g. jfrog artifactory), if you use one.
The modern maven build process and the IDE integrations (at least Idea anyway) will automatically configure the correct paths for compilation of the declared dependencies so that they are available from the module path if they are modular and the class path or as an automatic module if they are not modular.
Include the dependent jars in your package. This can be done two ways:
if the jars are modular, link the jars into the runtime image included in the package:
Both jlink and jpackage can do this, but when creating an installer, use jpackage for the linking not jlink as jpackage will ensure all files in the image are in the right location for the installer, but jlink will not, in my experience using Java 17 tools.
if the jars are not modular, then include them in a lib directory in the package. In the startup script for your application, which is included in the package, place the lib directory for the non-modular library files on the class path, so that they can be found.
Additionally, this dependency requires SnakeYAML, which I don't believe is a modular project?
Follow the tutorial at:
https://github.com/dlemmermann/JPackageScriptFX
A description of JPackageScriptFX:
demonstrates how projects can use scripts to build self-contained, platform-specific executables and installers of their JavaFX applications via the jdeps, jlink, and jpackage tools
the scripts do not try to create a fully modularized solution but instead try to enable existing projects / applications, which often use non-modularized 3rd party dependencies, to be packaged
I have an explicit modular project which is dependent on an automatic module; e.g. on java.activation. Is it still possible to use jlink?
See this module-info.java:
module hello {
requires java.activation;
}
Then jlink can't add the module:
$ jlink --module-path target/modules --add-modules hello --output target/jlink
Error: automatic module cannot be used with jlink: java.activation from file:///C:/Development/jlinkExample/target/modules/javax.activation-api-1.2.0.jar
From my understanding, an automatic module would contain the whole classpath anyway. So I guess there would be no benefit to creating a runtime image with jlink?
See also: What is an automatic module?
Are there any possibilities to circumvent this issue? Maybe generating a module-info.java for those dependencies?
From my understanding an automatic module would contain the whole
classpath anyway, so I guess there would be no benefit in creating a
runtime-image with jlink?
No, automatic modules would not contain the whole classpath. In fact, the artifacts which are not explicitly defined as modules(contain module-info.java) but are found on the modulepath are treated as automatic modules to bridge the gap between explicit modules and the classpath code.
Are there any possibilities to circumvent this issue, maybe generating
a module-info for those dependencies?
Yes, you can either create a module-info.java with jdeps or use plugins like moditect to generate module-info for the module and inject it in your existing JAR.
Once the artifact(JAR) has an explicit module declaration, jlink should accept it without failure.
I have a project (Java Swing application), in which I want to mix Java and Groovy.
I can compile and run the project without problems inside IntelliJ Idea.
But I can't compile it with Maven:
In src/main/groovy I define a Groovy class GroovyClass.
In src/main/java there is a Java class, which uses GroovyClass.
When compiling the project with Maven, I get the message [ERROR] ...\JavaClass.java:[13,47] error: cannot find symbol.
How can I change the pom.xml file in order to be able to compile and package the application using Maven?
Add the groovy-eclipse compiler maven plugin to your pom.xml
Instructions are on the plugins page at https://github.com/groovy/groovy-eclipse/wiki/Groovy-Eclipse-Maven-plugin