I'm trying to create a JFX11 self-containing jar using maven dependencies. From the research I've done, it seems the best way to do this is through the maven shade plugin. However, When I run it, I get the this error:
Error: JavaFX runtime components are missing, and are required to run this application
I don't understand why this is happening. What am I messing up? Is there a better way to do this? I've also tried the maven assembly plugin with the same message.
pom file for reference
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Application</groupId>
<artifactId>Main</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpaceRunner</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>10</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>Application.Main</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>
Application.Main
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Application.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
UPDATE 10/2021
Since JavaFX 16 a warning is displayed when JavaFX doesn't run on the module path, which is the case of an uber/fat jar:
$ java -jar myFatJar-1.0-SNAPSHOT.jar
Oct 02, 2021 1:45:21 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #14c24f4c'
Also, you get a warning from the shade plugin itself:
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
While these warnings can be initially ignored, there is a reason for them.
As explained in this CSR:
JavaFX is built and distributed as a set of named modules, each in its own modular jar file, and the JavaFX runtime expects its classes to be loaded from a set of named javafx.* modules, and does not support loading those modules from the classpath.
And:
when the JavaFX classes are loaded from the classpath, it breaks encapsulation, since we no longer get the benefit of the java module system.
Therefore, even this widely accepted answer explains how can an uber/fat jar can be created on Maven projects, its use is discouraged, and other modern alternatives to distribute your application, like jlink, jpackage or native-image, should be used.
ORIGINAL ANSWER
This answer explains why a fat/uber jar fails on JavaFX 11. In short:
This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the javafx.graphics module to be present as a named module. If that module is not present, the launch is aborted.
And already proposes a fix for Gradle.
For Maven the solution is exactly the same: provide a new main class that doesn't extend from Application.
You will have new class in your application package (bad name):
// NewMain.java
public class NewMain {
public static void main(String[] args) {
Main.main(args);
}
}
And your existing Main class, as is:
//Main.java
public class Main extends Application {
#Override
public void start(Stage stage) {
...
}
public static void main(String[] args) {
launch(args);
}
}
Now you need to modify your pom and set your main class for the different plugins:
<mainClass>application.NewMain</mainClass>
Platform-specific Fat jar
Finally, with the shade plugin you are going to produce a fat jar, on your machine.
This means that, so far, your JavaFX dependencies are using a unique classifier. If for instance you are on Windows, Maven will be using internally the win classifier. This has the effect of including only the native libraries for Windows.
So you are using:
org.openjfx:javafx-controls:11
org.openjfx:javafx-controls:11:win
org.openjfx:javafx-graphics:11
org.openjfx:javafx-graphics:11:win <-- this contains the native dlls for Windows
org.openjfx:javafx-base:11
org.openjfx:javafx-base:11:win
Now, if you produce the fat jar, you will bundle all those dependencies (and those other regular third party dependencies from your project), and you will be able to run your project as:
java -jar myFatJar-1.0-SNAPSHOT.jar
While this is very nice, if you want to distribute you jar, be aware that this jar is not cross-platform, and it will work only on your platform, in this case Windows.
Cross-Platform Fat Jar
There is a solution to generate a cross-platform jar that you can distribute: include the rest of the native libraries of the other platforms.
This can be easily done, as you just need to include the graphics module dependencies for the three platforms:
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>mac</classifier>
</dependency>
</dependencies>
Size
There is a main issue with this approach: the size. As you can see in this other answer, if you use the WebView control, you will be bundling around 220 MB due to the WebKit native libraries.
Related
I need to include a directory containing a python script and binaries that need to be executed by the script based on the parsed arguments in the JavaFX application.
The project is modular and built using Maven (although the modular part is not such an important piece of information).
When built using the maven run configuration, application works properly but for the purpose of creating a runtime image I stumble upon the problem of not having the script executed when I run the generated launcher .bat script in the "bin" folder of the "target".
For the purpose of generating the runtime, I have put the script directory in the project "resources" folder. The script is executed from the Java code using the Java Runtime.
Let's say the code looks like this:
pyPath = Paths.get("src/main/resources/script/main.py").toAbsolutePath().toString();
command = "python"+pyPath+args;
runtime = Runtime.getRuntime();
process = runtime.exec(command);
And pom.xml file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>gui</artifactId>
<version>1.0-SNAPSHOT</version>
<name>gui</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.8.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>11.1.1</version>
</dependency>
<dependency>
<groupId>com.dlsc.formsfx</groupId>
<artifactId>formsfx-core</artifactId>
<version>11.3.2</version>
<exclusions>
<exclusion>
<groupId>org.openjfx</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.kordamp.ikonli</groupId>
<artifactId>ikonli-javafx</artifactId>
<version>12.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>9.0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.5.2</version>
<configuration>
<name>gui</name>
<appVersion>1.0.0</appVersion>
<vendor>1234</vendor>
<destination>target/dist</destination>
<module>com.example.gui/com.example.gui.Application</module>
<runtimeImage>target/example-gui</runtimeImage>
<winDirChooser>true</winDirChooser>
<winPerUserInstall>true</winPerUserInstall>
<winShortcut>true</winShortcut>
<winMenuGroup>Applications</winMenuGroup>
<icon>${project.basedir}/main/resources/img/icon.ico</icon>
<javaOptions>
<option>-Dfile.encoding=UTF-8</option>
</javaOptions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>18</source>
<target>18</target>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<mainClass>com.example.gui/com.example.gui.Application</mainClass>
<launcher>gui-launcher</launcher>
<jlinkZipName>gui</jlinkZipName>
<jlinkImageName>gui</jlinkImageName>
<jlinkVerbose>true</jlinkVerbose>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<noHeaderFiles>true</noHeaderFiles>
<options>
<option>--add-opens</option><option>javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED</option>
<option>--add-opens</option><option>javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED</option>
<option>--add-opens</option><option>javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED</option>
<option>--add-opens</option><option>javafx.base/com.sun.javafx.binding=ALL-UNNAMED</option>
<option>--add-opens</option><option>javafx.graphics/com.sun.javafx.stage=ALL-UNNAMED</option>
<option>--add-opens</option><option>javafx.base/com.sun.javafx.event=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.base/com.sun.javafx.binding=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.graphics/com.sun.javafx.stage=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED</option>
<option>--add-exports</option><option>javafx.base/com.sun.javafx.event=ALL-UNNAMED</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
*Note: additional options for the javafx-maven-plugin are added for the jfoenix package compatibility
Also module-info.java
module com.example.gui {
requires javafx.controls;
requires javafx.fxml;
requires org.controlsfx.controls;
requires com.dlsc.formsfx;
requires org.kordamp.ikonli.javafx;
requires com.jfoenix;
opens com.example.gui to javafx.fxml;
exports com.example.gui;
}
Now the question is how do I include the script in the application runtime image, have it executed when I call the generated .bat for the application and finally packed using the jpackage?
Problems
The src/main/resources directory only exists in your project sources. It does not exist in the build output, and it definitely does not exist in your deployment location. In other words, using:
var pyPath = Paths.get("src/main/resources/script/main.py").toAbsolutePath().toString();
Will only work when your working directory is your project directory. It's also reading the "wrong" main.py resource, as the "correct" one will be in your target directory. Additionally, resources are not files. You must access resources using the resource-lookup API. For example:
var pyPath = getClass().getResource("/script/main.py").toString();
And note src/main/resources is not included in the resource name.
Executing the Script
But even after you correctly access the resource you still have a problem. Your script is a resource, which means it will be embedded in a JAR file or custom run-time image when deployed. I strongly doubt Python will know how to read and execute such a resource. This means you need to find a way to make the Python script a regular file on the host computer.
Potential Solutions
I can think of at least three approaches that may solve the problems described above. As I only have Windows, I can't promise the below examples will work on other platforms, or otherwise be easily translated for other platforms.
My examples don't include JavaFX, as I don't believe that's necessary to demonstrate how to include a Python script that is executed at runtime.
Here are some common aspects between all solutions.
module-info.java:
module com.example {}
main.py:
print("Hello from Python!")
1. Extract the Script at Runtime
One approach is to extract the Python script to a known location on the host computer at runtime. This is likely the most versatile solution, as it doesn't depend much on the way you deploy your application (jar, jlink, jpackage, etc.).
This example extracts the script to a temporary file, but you can use another location, such as an application-specific directory under the user's home directory. You can also code it to extract only if not already extracted, or only once per application instance.
I think this is the solution I would use, at least to start with.
Project structure:
| pom.xml
|
\---src
\---main
+---java
| | module-info.java
| |
| \---com
| \---example
| \---app
| Main.java
|
\---resources
\---scripts
main.py
Main.java:
package com.example.app;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws Exception {
Path target = Files.createTempDirectory("sample-1.0").resolve("main.py");
try {
// extract resource to temp file
try (InputStream in = Main.class.getResourceAsStream("/scripts/main.py")) {
Files.copy(in, target);
}
String executable = "python";
String script = target.toString();
System.out.printf("COMMAND: %s %s%n", executable, script); // log command
new ProcessBuilder(executable, script).inheritIO().start().waitFor();
} finally {
// cleanup for demo
Files.deleteIfExists(target);
Files.deleteIfExists(target.getParent());
}
}
}
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<name>sample</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>18</maven.compiler.release>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.app.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jlink-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>default-cli</id>
<phase>package</phase>
<goals>
<goal>jlink</goal>
</goals>
</execution>
</executions>
<configuration>
<classifier>win</classifier>
</configuration>
</plugin>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<id>default-cli</id>
<phase>package</phase>
<goals>
<goal>jpackage</goal>
</goals>
</execution>
</executions>
<configuration>
<type>APP_IMAGE</type>
<runtimeImage>${project.build.directory}/maven-jlink/classifiers/win</runtimeImage>
<module>com.example/com.example.app.Main</module>
<destination>${project.build.directory}/image</destination>
<winConsole>true</winConsole>
</configuration>
</plugin>
</plugins>
</build>
</project>
Build the project with:
mvn package
And then execute the built application image:
> .\target\image\sample\sample.exe
COMMAND: python C:\Users\***\AppData\Local\Temp\sample-1.015076039373849618085\main.py
Hello from Python!
2. Place the Script in the "Application Directory"
Disclaimer: I don't know if doing this is a smart or even supported approach.
This solution makes use of --input to place the script in the "application directory" of the application image. You can then get a reference to this directory by setting a system property via --java-options and $APPDIR. Note I tried to get this to work with the class-path, so as to not need the $APPDIR system property, but everything I tried resulted in Class#getResource(String) returning null.
The application directory is the app directory shown in this documentation.
As this solution places the Python script with the rest of the application image, which means it's placed in the installation location, you may be more likely to run into file permission issues.
Given the way I coded Main.java, this demo must be executed only after packaging with jpackage. I suspect there's a more robust way to implement this solution.
Project structure:
| pom.xml
|
+---lib
| \---scripts
| main.py
|
\---src
\---main
\---java
| module-info.java
|
\---com
\---example
\---app
Main.java
Main.java:
package com.example.app;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws Exception {
String executable = "python";
String script = Path.of(System.getProperty("app.dir"), "scripts", "main.py").toString();
System.out.printf("COMMAND: %s %s%n", executable, script); // log command
new ProcessBuilder(executable, script).inheritIO().start().waitFor();
}
}
pom.xml:
(this is only the <configuration> of the org.panteleyev:jpackage-maven-plugin plugin, as everything else in the POM is unchanged from the first solution)
<configuration>
<type>APP_IMAGE</type>
<runtimeImage>${project.build.directory}/maven-jlink/classifiers/win</runtimeImage>
<input>lib</input>
<javaOptions>
<javaOption>-Dapp.dir=$APPDIR</javaOption>
</javaOptions>
<module>com.example/com.example.app.Main</module>
<destination>${project.build.directory}/image</destination>
<winConsole>true</winConsole>
</configuration>
Build the project with:
mvn package
And then execute the built application image:
> .\target\image\sample\sample.exe
COMMAND: python C:\Users\***\Desktop\sample\target\image\sample\app\scripts\main.py
Hello from Python!
3. Add the Script as Additional "App Content"
Disclaimer: Same as the disclaimer for the second solution.
This would make use of the --app-content argument when invoking jpackage. Unfortunately, I could not figure out how to configure this using Maven, at least not with the org.panteleyev:jpackage-maven-plugin plugin. But essentially this solution would have been the same as the second solution above, but with --input removed and --app-content lib/scripts added. And a slight change to how the script Path is resolved in code.
The --app-content argument seems to put whatever directories/files are specified in the root of the generated application image. I'm not sure of a nice convenient way to get this directory, as the application image structure is slightly different depending on the platform. And as far as I can tell, there's no equivalent $APPDIR for the image's root directory.
I'm using the current NetBeans, and have just created a simple JavaFX project with the Maven compiler.
It runs, cleans, builds etc. perfectly fine, no errors, when in NetBeans.
However, when I navigate to the folder "...Documents\NetBeansProjects\Simple Banking Application\target" and run the executable Jar file, nothing happens. So I tried to run it manually via command line (Java -jar file.jar) it shows me the reason is because of an error:
No main manifest attribute
After searching, I found a supposed solution, involving adding these few lines to the POM.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mycompany.mavenproject2.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Unfortunately, that just causes a new error:
Error: Could not find or load main class com.mycompany.mavenproject2.App
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application
I'm at a loss, and I'm wondering if I'm just missing something obvious. A couple of preliminary notes:
-I made sure to set this as my main project in NB
-I'm using default configuration
-I've tried cleaning and building, and just building as well, everything runs without any errors in NB
-I've not modified anything settings-wises
-I did refactor the project from mavenproject2 to Simple Banking Application, but I did so using NB's renaming options so that it does so 'safely'. (For the artifactID I had to remove the whitespaces)
-I've made sure all the .class files and .java files are in the project folder (.java are found in src, .class are found in target>classes)
Just in case, here is my entire POM.xml document:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>SimpleBankingApplication</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mycompany.mavenproject2.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<mainClass>com.mycompany.mavenproject2.App</mainClass>
</configuration>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
</execution>
<execution>
<!-- Configuration for manual attach debugging -->
<!-- Usage: mvn clean javafx:run#debug -->
<id>debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE debugging -->
<id>ide-debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE profiling -->
<id>ide-profile</id>
<configuration>
<options>
<option>${profiler.jvmargs.arg1}</option>
<option>${profiler.jvmargs.arg2}</option>
<option>${profiler.jvmargs.arg3}</option>
<option>${profiler.jvmargs.arg4}</option>
<option>${profiler.jvmargs.arg5}</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<name>Simple Banking Application</name>
</project>
You don't have the JavaFX components on your module path.
You can use a JDK which includes JavaFX (e.g. Azul JDK FX or Liberica Full JDK).
OR, you can follow the instructions below.
See the section on setting the VM arguments for running a JavaFX application as a jar file.
java --module-path /path/to/javafx-sdk-14/lib --add-modules javafx.controls,javafx.fxml -jar myJar.jar
You are using netbeans + maven, so refer to the official documentation openjfx.io JavaFX and NetBeans: modular with maven for more information. It discusses VM arguments for the Java module system to support JavaFX as well as creating runtime images using jlink.
If you don't know or understand the basics of the Java module system, then you should take some time to study and learn it from an appropriate tutorial. That will help you better understand the command line arguments required for the module system as well as the module-info.java alternative.
See the packaging instructions in the JavaFX tag which provide information on packaging alternatives (e.g. jlink and jpackage).
Use up-to-date software (e.g. JDK/JavaFX 18 and the maven-jar-plugin 0.0.8).
Don't use the maven-jar-plugin addClasspath option to build your jar when you have JavaFX component dependencies. The JavaFX components are not designed to be run from the classpath.
I am stuck trying to compile and test a extremely simple project. It's a beginner project in order to understand how all of this works, and I am currently stucked.
My main objective is to understand how to handle resources files that are located outside of the standard folder structure.
I have a main class, with two methods. One load a resource file which is on the standard folder structure (src\main\resources). Another one load a resource which is in a custom folder, outside of the standard structure (resources).
There is one junit file that simply verify that the resource is correctly loaded.
It works fine with IntelliJ. I simply declared the resources folder as resources folders and that's it.
Now with maven ..... actually I can't even compile with gmaven-plus. Nor run the test. So I did not even bother to declare the custom folder as a resource in the pom.xml file.
I based my pom.xml file based on an existing pom we have at work and from stuff I read on the web. There's no way I can make it work.
Here is a link to a 7zip file with my project, if one could put me on the right track, I would be grateful.
https://www.dropbox.com/s/jvn32ll5xfvjfwd/GroovyExample.7z?dl=0
Here is the pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>groupId</groupId>
<artifactId>Example</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.13</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compileTests</goal>
</goals>
<configuration>
<sources>
<source>
<directory>src/main/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</source>
</sources>
<testSources>
<testSource>
<directory>src/test/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</testSource>
</testSources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M1</version>
<configuration>
<failIfNoTests>true</failIfNoTests>
<testSourceDirectory>str/test/</testSourceDirectory>
<includes>
<include>**/*Test*.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Here is the output:
Unable to get Groovy version from InvokerHelper or GroovySystem,
trying jar name.
Failed to execute goal
org.codehaus.gmavenplus:gmavenplus-plugin:1.8.1:compile (default) on
project Example: Execution default of goal
org.codehaus.gmavenplus:gmavenplus-plugin:1.8.1:compile failed.
The 2.4 groovy-all POMs do not include Groovy as a dependency, because they are a POM for an uber-jar, rather than a POM that describes all the Groovy module jars. Because of this, GMavenPlus is unable to find the Groovy jar to use for compilation. The <type>pom</type> works for Groovy 2.5, and 3.0, but not 2.4. So for your use case, simply delete the <type>pom</type> (or replace it with the default of <type>jar</type>). This was the way Groovy was often included back before 2.5, so the groovy-all POMs of 2.5 and 3.0 were added to ease the transition. See https://groovy-lang.org/releasenotes/groovy-2.5.html#Groovy2.5releasenotes-Packaging.
I read all of the modular documentation but still cannot figure out what the problem is here: I added a dependency via Maven (I also tried adding the jar into project library manually but still caused the same problem), but when I import the class from that particular into my class, IntelliJ says "package com.fazecast.jSerialComm is declared in module 'com.fazecast.jSerialComm' but module com.greeting does not read it".
It gives me two options: Either add it as Maven dependency which I already did (it is in my pom.xml and can see it under dependencies) or "add requires com.fazecast.jSerialComm directive to module-info.java". If I add requires com.fazecast.jSerialComm, it compiles fine, but when I create my modular jar and try to run the jar with java -p mods/ -m com.greeting/com.mayapp.Runner, it tells me "java.lang.module.FindException: Module com.fazecast.jSerialComm not found, required by com.greeting".
I also tried more jars/dependencies which I have and it gave me the same problem. I tried Java 9 and 10, also with Gradle, and created artifact via IntelliJ. Got the same exception. My module-info.java is in src/main/java as where my app starts. Any help will be highly appreciated.
Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T14:33:14-04:00)
Maven home: C:\Apache\apache-maven-3.5.4-bin\apache-maven-3.5.4\bin\..
Java version: 9.0.4, vendor: Oracle Corporation, runtime: C:\Program iles\Java\jdk-9.0.4 Default locale: en_US, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
Intelli J 2018.1.6
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myapp</groupId>
<artifactId>greet</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>10</source>
<target>10</target>
<release>9</release>
<executable>javac10</executable>
<compilerArgs>
<arg>-Xlint:all,-processing</arg>
</compilerArgs>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
package com.myapp;
import com.fazecast.jSerialComm.SerialPort;
public class Runner {
public static void main(String[] args) {
System.out.println("Runner");
}
}
module com.greeting {
requires com.fazecast.jSerialComm;
}
If you develop a module (as indicated by your module-info.java), all dependencies need to be required (that's the quick fix IntelliJ recommended) and need to be on the module path (instead of the class path) for compilation and launch. For compilation, Maven, Gradle, and IntelliJ do the right thing and when launching your app from IntelliJ, it will do that as well.
The problem most likely lies with your java command:
java -p mods/ -m com.greeting/com.mayapp.Runner
It points to mods as the module path, but unless you forgot to mention some steps you undertook, that folder does not contain your app's dependencies, so when Java goes looking for them, it will not find them - thus the error message.
To get your dependencies into that folder you can either copy them manually (don't forget transitive dependencies) or use Maven's copy-dependencies mojo for that:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/../mods</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
When you run mvn package or mvn install, you will find all dependencies, including transitive ones, in mods and then your command should work.
I am trying to connect to the smartsheet api using a java program.
Initially I had problems with the site certificate which was resolved by adding it to the java keystore. Now when I am trying to run my code, I get the following error.
Exception in thread "main" java.lang.NoSuchFieldError: INSTANCE
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:144)
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:955)
at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:58)
at com.smartsheet.api.internal.http.DefaultHttpClient.<init>(DefaultHttpClient.java:64)
at com.smartsheet.api.SmartsheetBuilder.build(SmartsheetBuilder.java:203)
at SmartsheetConnection.main(SmartsheetConnection.java:13)
This is my code (I followed their documentation).
import com.smartsheet.api.*;
import com.smartsheet.api.models.*;
import com.smartsheet.api.models.enums.*;
import com.smartsheet.api.oauth.*;
public class SmartsheetConnection {
public static void main(String[] args) throws SmartsheetException {
// Set the access token.
Token token = new Token();
token.setAccessToken("foo");
Smartsheet smartsheet = new SmartsheetBuilder().setAccessToken(token.getAccessToken()).build();
}
}
The line that is throwing error is (line 144)
#Deprecated
public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
= AllowAllHostnameVerifier.INSTANCE;
but I am not sure what to make of it. I am using maven to get the dependencies. Does it have something to do with the version of the Apache HttpComponents?
Here is the pom.xml
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.smartsheet</groupId>
<artifactId>smartsheet-sdk-java</artifactId>
<version>2.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
Other posts about this error seem to suggest that it's typically caused by conflicting versions of httpcore jar. i.e., an older version of httpcore on the classpath.
For more information, I'd suggest you checkout the following posts:
java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE from Mashape Unirest in Java application
java.lang.NoSuchFieldError: INSTANCE
I know its I am replying a bit late actually I am also struggling the same problem and I found the solution by using Maven Shade plugin.
The Problem is the JAR conflict probably your project is using a different Version Of HTTPclient then your container over which your Appliaction is running.
To resolve this use the Below Maven Shade Plugin which will change the package name of HttpClient to the specified one which packaging the JAR. This will also refactor all the usage in your code.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.apache.http</pattern>
<shadedPattern>org.shaded.apache.http</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
The Above sample will change HttpClient Package with org.shaded.apache.http from org.apache.http
Maven Shade will also create a fat/uber jar so your final package size get increased and will have all the classes which you have mentioned in the Dependency in POM.
If you don't want to include the all your dependency jar in your final jar then add the Scope for the Dependency as <scope>provided</scope>.
the reason for this problem is:
org.apache.http.conn.ssl.AllowAllHostnameVerifier class,which is execused in the runtime,has no field 'INSTANCE'.
My project classpath contains two same name class of "org.apache.http.conn.ssl.AllowAllHostnameVerifier".
One cames from a jar customized by our company,which has no field 'INSTANCE'.
Another cames from maven central repository,which has the field 'INSTANCE'.
My code sometimes run the logic of the latter jar and sometimes the fromer jar,which is the reason I guessed.
my classpath search result
the comparison of the two jar
I was using intellij for both android and spring development.
In my case, I accidentally chose Android sdk as the module SDK.
After choosing JDK 1.8 and rebuilding the project fixed the issue for me