openjdk-jfx icon indicating copy to clipboard operation
openjdk-jfx copied to clipboard

Include dependencies in jar

Open klausenbusk opened this issue 7 years ago • 15 comments

Hi

I'm trying to include all the (openjfx) dependencies in a fat jar so it can be run without OpenJFX installed. I have successfully built a .jar file contained all the dependencies (I think), but for whatever reason I get: Error: JavaFX runtime components are missing, and are required to run this application. I'm not sure if this is a bug or just a lack of knowledge. Either way, I think a working example could be useful.

pom.xml (copy HelloFX.java to src/)

<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>HelloFX</groupId>
  <artifactId>HelloFX</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <release>10</release>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>HelloFX</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>HelloFX</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <dependencies>
  	<dependency>
  		<groupId>org.openjfx</groupId>
  		<artifactId>javafx-controls</artifactId>
  		<version>11</version>
  	</dependency>
  </dependencies>
</project>
$ mvn --version
Apache Maven 3.5.4 (NON-CANONICAL_2018-09-08T01:02:16+02:00_root; 2018-09-08T01:02:16+02:00)
Maven home: /opt/maven
Java version: 10.0.2, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-10-openjdk
Default locale: da_DK, platform encoding: UTF-8
OS name: "linux", version: "4.18.10-arch1-1-arch", arch: "amd64", family: "unix"
$ java --version
openjdk 10.0.2 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13)
OpenJDK 64-Bit Server VM (build 10.0.2+13, mixed mode)

klausenbusk avatar Oct 03 '18 08:10 klausenbusk

So LauncherHelper.java abort as the module javafx.graphics isn't available and a single jar can only contain a single module (?).

So a self-contained .jar with OpenJFX seems to be unsupported at the moment?

klausenbusk avatar Oct 03 '18 09:10 klausenbusk

I can try later to reproduce, but you are using Java 10, which includes JavaFX, and then adding JavaFX 11 dependencies. That looks like a bad idea.

nlisker avatar Oct 03 '18 10:10 nlisker

The reason is that the Java 11 runtime will check if the main class extends javafx.application.Application, and if that is the case, it strongly requires the javafx platform to be available as a module, and not as a jar for example. It was discussed here: http://mail.openjdk.java.net/pipermail/openjfx-dev/2018-June/021977.html

While going modular is definitely the way to go, I still think it's unfortunate that JavaFX applications are treated a bit different here from other application (where you can still use the classpath).

There are some easy workarounds though. For example, you can have a main class that is not extending javafx.application.Application, and that main class can then call the main(String[]) method on your real main class (that way, the Java launcher doesn't require the javafx libraries to be available as named modules). See https://stackoverflow.com/questions/52569724/javafx-11-create-a-jar-file-with-gradle/52571719#52571719 or https://stackoverflow.com/questions/52569724/javafx-11-create-a-jar-file-with-gradle/52615808#52615808

johanvos avatar Oct 03 '18 10:10 johanvos

I can try later to reproduce, but you are using Java 10, which includes JavaFX, and then adding JavaFX 11 dependencies. That looks like a bad idea.

OpenJDK does not include OpenJFX as far as I know?

There are some easy workarounds though. For example, you can have a main class that is not extending javafx.application.Application, and that main class can then call the main(String[]) method on your real main class (that way, the Java launcher doesn't require the javafx libraries to be available as named modules).

Thanks, now it works. Next step I need to figure out how to bundle all the native libraries (windows, mac, linux) instead of only one.

klausenbusk avatar Oct 03 '18 10:10 klausenbusk

OpenJDK does not include OpenJFX as far as I know?

Only from 11. You are using Java 10, which includes JavaFX 10.

nlisker avatar Oct 03 '18 10:10 nlisker

Java 10

Oracle JDK 10 include JavaFX, OpenJDK 10 does not. I'm using OpenJDK 10.

klausenbusk avatar Oct 03 '18 10:10 klausenbusk

Sorry, I quickly saw Java version: 10.0.2, vendor: Oracle Corporation and thought you were using Oracle JDK 10.

nlisker avatar Oct 03 '18 11:10 nlisker

Working example: src/Main.java

public class Main {

    public static void main(String[] args) {
        HelloFX.main(args);
    }
}

src/HelloFX.java

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
//import javafx.graphics;

public class HelloFX extends Application {

    @Override
    public void start(Stage stage) {
        String javaVersion = System.getProperty("java.version");
        String javafxVersion = System.getProperty("javafx.version");
        Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
        Scene scene = new Scene(l, 640, 480);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>HelloFX</groupId>
  <artifactId>HelloFX</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <release>10</release>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>Main</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>Main</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <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>
</project>

klausenbusk avatar Oct 03 '18 11:10 klausenbusk

We also ran into Error: JavaFX runtime components are missing, and are required to run this application. The only thing we had to change in our pom.xml was setting a regular Java class as entry point which then called a JavaFX Application in its main like @klausenbusk showed.

kepakiano avatar Oct 04 '18 08:10 kepakiano

Can't thank you enough @klausenbusk

ScalaWilliam avatar Nov 04 '19 22:11 ScalaWilliam

Ran into this just now, when running the Non Modular Gradle sample from Intellij on Java 11. The message "Error: JavaFX runtime components are missing, and are required to run this application" sounds like something fundamental is missing from your system. But you can just create another class (which doesn't subclass Application) with a main method which simply calls your Application-class main method - and it then works from Intellij You will have people giving up on Java FX because of this issue - I nearly did myself!

davidfrancisandroidemul avatar Jul 27 '20 11:07 davidfrancisandroidemul

Isn't it mentioned in https://openjfx.io/openjfx-docs/?

On Mon, Jul 27, 2020 at 2:27 PM davidfrancisandroidemul < [email protected]> wrote:

Ran into this just now, when running the Non Modular Gradle sample from Intellij on Java 11. The message "Error: JavaFX runtime components are missing, and are required to run this application" sounds like something fundamental is missing from your system. But you can just create another class (which doesn't subclass Application) with a main method which simply calls your Application-class main method - and it then works from Intellij You will have people giving up on Java FX because of this issue - I nearly did myself!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/javafxports/openjdk-jfx/issues/236#issuecomment-664340032, or unsubscribe https://github.com/notifications/unsubscribe-auth/AI5QOM55UYBVWWYNRXV6O4LR5VQAHANCNFSM4FYWJUHQ .

nlisker avatar Jul 27 '20 14:07 nlisker

@davidfrancisandroidemul Also note that this repo is defunct. The current one is https://github.com/openjdk/jfx.

nlisker avatar Jul 27 '20 14:07 nlisker

The error is indeed mentioned, but in a different section than the one I was following And the solution documented in there didn't work Before I found the "create a new class" solution, I did clone the samples from the page (linked above by nlisker) and tried them - got the same error 8[

OK will try the new repo, maybe the new examples work?

connorsadler avatar Jul 27 '20 14:07 connorsadler

I've never had a problem with the instructions, so from my point of view the examples worked and still work.

If you have a problem specifically with the examples, file an issue with https://github.com/openjfx/openjfx.github.io, which is the repository for the openjfx.io website. The https://github.com/openjdk/jfx repository is for issues with JavaFX itself.

nlisker avatar Jul 27 '20 22:07 nlisker