admin管理员组

文章数量:1388225

You can checkout my whole project on github. I currently don't use any dependency managers in my projects and I would like to keep it that way. I am using a library that I made in java and I am using javaFX for GUI. As the title states I want to make my app a standalone app so someone can run it without having java installed.

I make my jar file like this in VSCode:

And after this I can run my application with .jar file with this command:

java --module-path %JAVAFX% --add-modules=javafx.controls,javafx.fxml -jar match_three_solver.jar

So I try to run this command jdeps -s --module-path %JAVAFX% match_three_solver.jar to check which packages I have to include in my jlink command and it returns me this error:

Exception in thread "main" java.lang.module.FindException: Error reading module: match_three_solver.jar
        at java.base/jdk.internal.module.ModulePath.readModule(ModulePath.java:351)
        at java.base/jdk.internal.module.ModulePath.scan(ModulePath.java:238)
        at java.base/jdk.internal.module.ModulePath.scanNextEntry(ModulePath.java:191)
        at java.base/jdk.internal.module.ModulePath.findAll(ModulePath.java:167)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:521)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:607)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:561)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:537)
        at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:50)
Caused by: java.lang.module.InvalidModuleDescriptorException: Main.class found in top-level directory (unnamed package not allowed in module)
        at java.base/jdk.internal.module.ModulePath.toPackageName(ModulePath.java:720)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
        at java.base/java.util.zip.ZipFile$EntrySpliterator.tryAdvance(ZipFile.java:573)
        at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at java.base/jdk.internal.module.ModulePath.jarPackages(ModulePath.java:621)
        at java.base/jdk.internal.module.ModulePath.lambda$readJar$6(ModulePath.java:653)
        at java.base/jdk.internal.module.ModuleInfo.doRead(ModuleInfo.java:311)
        at java.base/jdk.internal.module.ModuleInfo.read(ModuleInfo.java:129)
        at java.base/jdk.internal.module.ModulePath.readJar(ModulePath.java:652)
        at java.base/jdk.internal.module.ModulePath.readModule(ModulePath.java:332)
        ... 8 more

If I understand this correctly (I don't know really what I am doing cuz I'm doing this for the first time)... I have a non-modular .jar file so I can't use jdeps. If I want to use jdeps command I have to have module-info.java in my project. My issue is that wherever I create module-info.java file... the compiler starts screaming errors and it also doesn't recognize javafx modules:

So if you have any idea how to fix this (if I have to completely restructure the current folder to make it work) please let me know. Also what is the point that I can't use jdeps without my .jar file being a modular.

Also I tired to just make my standalone app with this command

jlink --module-path ../jmods;lib/javaFX/lib 
--add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.web 
--output jreFX2

and run it like this (in its standalone environment) jreFX2\bin\java -jar match_three_solver.jar... And it gives me this error:

Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:283)
        at [email protected]/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:253)
        at [email protected]/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:263)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
        at [email protected]/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1135)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:95)
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1135)
Caused by: java.lang.RuntimeException: No toolkit found
        at [email protected]/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:275)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
        at [email protected]/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        ... 2 more

Any help would be greatly appreciated. Thanks in advance.

You can checkout my whole project on github. I currently don't use any dependency managers in my projects and I would like to keep it that way. I am using a library that I made in java and I am using javaFX for GUI. As the title states I want to make my app a standalone app so someone can run it without having java installed.

I make my jar file like this in VSCode:

And after this I can run my application with .jar file with this command:

java --module-path %JAVAFX% --add-modules=javafx.controls,javafx.fxml -jar match_three_solver.jar

So I try to run this command jdeps -s --module-path %JAVAFX% match_three_solver.jar to check which packages I have to include in my jlink command and it returns me this error:

Exception in thread "main" java.lang.module.FindException: Error reading module: match_three_solver.jar
        at java.base/jdk.internal.module.ModulePath.readModule(ModulePath.java:351)
        at java.base/jdk.internal.module.ModulePath.scan(ModulePath.java:238)
        at java.base/jdk.internal.module.ModulePath.scanNextEntry(ModulePath.java:191)
        at java.base/jdk.internal.module.ModulePath.findAll(ModulePath.java:167)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:521)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:607)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:561)
        at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:537)
        at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:50)
Caused by: java.lang.module.InvalidModuleDescriptorException: Main.class found in top-level directory (unnamed package not allowed in module)
        at java.base/jdk.internal.module.ModulePath.toPackageName(ModulePath.java:720)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
        at java.base/java.util.zip.ZipFile$EntrySpliterator.tryAdvance(ZipFile.java:573)
        at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at java.base/jdk.internal.module.ModulePath.jarPackages(ModulePath.java:621)
        at java.base/jdk.internal.module.ModulePath.lambda$readJar$6(ModulePath.java:653)
        at java.base/jdk.internal.module.ModuleInfo.doRead(ModuleInfo.java:311)
        at java.base/jdk.internal.module.ModuleInfo.read(ModuleInfo.java:129)
        at java.base/jdk.internal.module.ModulePath.readJar(ModulePath.java:652)
        at java.base/jdk.internal.module.ModulePath.readModule(ModulePath.java:332)
        ... 8 more

If I understand this correctly (I don't know really what I am doing cuz I'm doing this for the first time)... I have a non-modular .jar file so I can't use jdeps. If I want to use jdeps command I have to have module-info.java in my project. My issue is that wherever I create module-info.java file... the compiler starts screaming errors and it also doesn't recognize javafx modules:

So if you have any idea how to fix this (if I have to completely restructure the current folder to make it work) please let me know. Also what is the point that I can't use jdeps without my .jar file being a modular.

Also I tired to just make my standalone app with this command

jlink --module-path ../jmods;lib/javaFX/lib 
--add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.web 
--output jreFX2

and run it like this (in its standalone environment) jreFX2\bin\java -jar match_three_solver.jar... And it gives me this error:

Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:283)
        at [email protected]/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:253)
        at [email protected]/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:263)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
        at [email protected]/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1135)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:95)
        at [email protected]/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1135)
Caused by: java.lang.RuntimeException: No toolkit found
        at [email protected]/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:275)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:290)
        at [email protected]/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
        at [email protected]/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:651)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409)
        at [email protected]/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        ... 2 more

Any help would be greatly appreciated. Thanks in advance.

Share Improve this question asked Mar 18 at 21:03 DimnikDimnik 796 bronze badges 19
  • 3 jlink will only work if your project and all libraries transitively used are full modules (have module-info.java defined). The JavaFX getting started instructions include info on creating projects using Visual Studio. For modular projects in Visual Studio it only includes instructions to do that using Maven or Gradle. I recommend you follow that even though you don't want to. You likely don't need to use jdeps at all. – jewelsea Commented Mar 18 at 22:07
  • For creating run time images using jlink, the getting started section titled "Runtime images" contains instructions for doing that from the command line, or using Maven or Gradle. So follow those instructions, whichever is appropriate. Start first with the example "hello, world" project from the instructions before trying to apply them to your code. – jewelsea Commented Mar 18 at 22:09
  • For your last error ("no toolkit found"), make sure the native code is included in the runtime image created by jlink. See this Q&A. – Slaw Commented Mar 18 at 22:14
  • 1 They both have a decent learning curve, but I believe Maven is easier to learn for beginners than Gradle is. Maven's build files are in XML format, so they'll be verbose but straightforward. Whereas Gradle's build files are written in Groovy and/or Kotlin (both full programming languages), which can make it harder to understand and easily lead to overly complex build files. That said, both Maven and Gradle are decently documented. And both are industry standards, so there'll be a lot of tutorials out there and any major Java frameworks will likely have plugins for both. – Slaw Commented Mar 19 at 6:30
  • 2 Solution for creating an exe without an installer (in case you need that). – jewelsea Commented Mar 22 at 0:57
 |  Show 14 more comments

3 Answers 3

Reset to default 2

The lazy and quick way: Download azul JRE (with JavaFX)

Distibution Directory

match_three_solver_app
├── jre
├── match_three_solver.jar
└── runMe.bat

Create app directory

Create app directory : match_three_solver_app

Your app jar

  • match_three_solver.jar download from your github project

runMe.bat

create runMe.bat into app directory : match_three_solver_app

start /B "" jre\bin\javaw -jar match_three_solver.jar
exit

jre

Download JRE with JavaFX

https://www.azul/downloads/?package=jdk#zulu

  • Java Version: Java 21 (LTS)
  • Operating System: Windows
  • Architecture: x86_64
  • Java Package: JRE_FX
  • Download: zip

get zulu21.40.17-ca-fx-jre21.0.6-win_x64.zip

unzip Download JRE zip

unzip zulu21.40.17-ca-fx-jre21.0.6-win_x64.zip

ren directory zulu21.40.17-ca-fx-jre21.0.6-win_x64 to jre

put jre directory into app directory : match_three_solver_app

Final Distibution Directory

match_three_solver_app
├── jre
├── match_three_solver.jar
└── runMe.bat

Now you can compress the match_three_solver_app directory into a zip archive.

match_three_solver_app.zip

Others only need to get match_three_solver_app.zip, unzip it, and click runMe.bat in the directory to run match_three_solver.

Summarize

  • First of all, this approach is lazy and quick to accomplish your needs: Users do not need to download JRE themselves.
  • Second, you don't need to understand jlink and jpackage.

What are its disadvantages:

  • First of all, its file size is very large. Because jre includes the complete jre and javafx.
  • Second, you need to carefully read the license terms of zulu Jre.

The following steps outline the process of creating a custom JRE:

JDK

Download JDK

https://adoptium/temurin/releases/?os=windows&arch=x64&package=jdk

  • Operating System: Windows
  • Architecture: x64
  • Package Type: JDK
  • Version: 21-LTS
  • Download: .zip

get OpenJDK21U-jdk_x64_windows_hotspot_21.0.6_7.zip

Unzip JDK

unzip OpenJDK21U-jdk_x64_windows_hotspot_21.0.6_7.zip

move jdk-21.0.6+7 to C:\TOOLS

final path is C:\TOOLS\jdk-21.0.6+7

Config User Environment Variables

  • New JAVA_HOME SET C:\TOOLS\jdk-21.0.6+7
  • PATH ADD C:\TOOLS\jdk-21.0.6+7\bin

JavaFX JMODS

Download JavaFX

https://gluonhq/products/javafx/

  • JavaFX version: 21.0.6[LTS]
  • Operating System: Windows
  • Architecture: 64
  • Type: jmods

get openjfx-21.0.6_windows-x64_bin-jmods.zip

Unzip JavaFX

unzip openjfx-21.0.6_windows-x64_bin-jmods.zip

move javafx-jmods-21.0.6 into C:\TOOLS

final path is C:\TOOLS\javafx-jmods-21.0.6

Config User Environment Variables

  • New JAVA_JMODS SET C:\TOOLS\jdk-21.0.6+7\jmods
  • New JAVAFX_JMODS SET C:\TOOLS\javafx-jmods-21.0.6

Create custom JRE

open cmd.exe

run command:

jlink --module-path %JAVA_JMODS%;%JAVAFX_JMODS% ^
      --add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.swing,java.desktop,java.base ^
      --output jreFX2

Distibution Directory

match_three_solver_app
├── jreFX2
├── match_three_solver.jar
└── runMe.bat

Create app directory

Create app directory : match_three_solver_app

Your app jar

  • match_three_solver.jar download from your github project

runMe.bat

create runMe.bat into app directory : match_three_solver_app

start /B "" jreFX2\bin\javaw -jar match_three_solver.jar
exit

Final Distibution Directory

match_three_solver_app
├── jreFX2
├── match_three_solver.jar
└── runMe.bat

Now you can compress the match_three_solver_app directory into a zip archive.

match_three_solver_app.zip

Others only need to get match_three_solver_app.zip, unzip it, and click runMe.bat in the directory to run match_three_solver.

Summarize

Here the directory size of custom JRE: jreFX2 is 106.3 MB

The following is how to create a windows installer msi file using jdk jpackage.

JDK

Download JDK

https://adoptium/temurin/releases/?os=windows&arch=x64&package=jdk

  • Operating System: Windows
  • Architecture: x64
  • Package Type: JDK
  • Version: 21-LTS
  • Download: .zip

get OpenJDK21U-jdk_x64_windows_hotspot_21.0.6_7.zip

Unzip JDK

unzip OpenJDK21U-jdk_x64_windows_hotspot_21.0.6_7.zip

move jdk-21.0.6+7 to C:\TOOLS

final path is C:\TOOLS\jdk-21.0.6+7

Config User Environment Variables

  • New JAVA_HOME SET C:\TOOLS\jdk-21.0.6+7
  • PATH ADD C:\TOOLS\jdk-21.0.6+7\bin

JavaFX JMODS

Download JavaFX

https://gluonhq/products/javafx/

  • JavaFX version: 21.0.6[LTS]
  • Operating System: Windows
  • Architecture: 64
  • Type: jmods

get openjfx-21.0.6_windows-x64_bin-jmods.zip

Unzip JavaFX

unzip openjfx-21.0.6_windows-x64_bin-jmods.zip

move javafx-jmods-21.0.6 into C:\TOOLS

final path is C:\TOOLS\javafx-jmods-21.0.6

Config User Environment Variables

  • New JAVA_JMODS SET C:\TOOLS\jdk-21.0.6+7\jmods
  • New JAVAFX_JMODS SET C:\TOOLS\javafx-jmods-21.0.6

Wix 3 (for jpackage create windows msi)

Download Wix3

https://github/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip

get wix311-binaries.zip

Unzip Wix3

unzip wix311-binaries.zip

move wix311-binaries into C:\TOOLS

final path is C:\TOOLS\wix311-binaries

Config User Environment Variables

  • PATH ADD C:\TOOLS\wix311-binaries

Your Github Project : match_three_solver

  • download match_three_solver-main.zip
  • unzip match_three_solver-main.zip

Project Directory

match_three_solver-main
├── README.md
├── match_three_solver.jar
├── match.three.solver.jpackage.settings (*)
├── input1.png
├── input2.png
├── input.png
├── bin
├── lib
├── src
└── target 
    └── lib
        └── match_three_solver.jar (*)
  • create sub directory : target\lib
  • copy match_three_solver.jar into target\lib

match.three.solver.jpackage.settings

create new file match.three.solver.jpackage.settings

--name match-three-solver
--input target\lib
--main-jar match_three_solver.jar
--java-options "-ms64m"
--java-options "-mx512m"
--type msi
--win-shortcut
--win-shortcut-prompt
--win-menu
--win-menu-group Game
--win-dir-chooser
--description "match three solver"
--vendor match.three.solver
--app-version 1.0.0
--add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.swing,java.desktop,java.base
--module-path C:\TOOLS\jdk-21.0.6+7\jmods;C:\TOOLS\javafx-jmods-21.0.6

Create Windows installer MSI

in project directory

open cmd.exe run command

cd match_three_solver-main

run command:

jpackage @match.three.solver.jpackage.settings

Every jpackage parameter is put in the file match.three.solver.jpackage.settings.

get file: match-three-solver-1.0.0.msi

file size: 38.5 MB (40,386,747 bytes)

本文标签: javaProblems with jlinking javafx modules to make stand alone aplicationStack Overflow