Skip to content
This repository has been archived by the owner on Jun 24, 2021. It is now read-only.

Include dependencies in jar #236

Open
klausenbusk opened this issue Oct 3, 2018 · 15 comments
Open

Include dependencies in jar #236

klausenbusk opened this issue Oct 3, 2018 · 15 comments
Labels
question Further information is requested

Comments

@klausenbusk
Copy link

klausenbusk commented Oct 3, 2018

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
Copy link
Author

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?

@nlisker
Copy link

nlisker commented Oct 3, 2018

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.

@johanvos
Copy link
Collaborator

johanvos commented Oct 3, 2018

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

@klausenbusk
Copy link
Author

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.

@nlisker
Copy link

nlisker commented Oct 3, 2018

OpenJDK does not include OpenJFX as far as I know?

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

@klausenbusk
Copy link
Author

Java 10

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

@nlisker
Copy link

nlisker commented Oct 3, 2018

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

@klausenbusk
Copy link
Author

klausenbusk commented Oct 3, 2018

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>

@kepakiano
Copy link

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.

@ScalaWilliam
Copy link

Can't thank you enough @klausenbusk

ghost pushed a commit to astefenc/CSE360Project that referenced this issue Dec 7, 2019
Never again.  Please.  This took way too long to find a tool that would make it.  And honestly, it's unlikely I could replicate it if I tried.

Nonetheless, here's some avenues to look into if you need it.
Gradle, (not Maven) for building the project.
I used Gradle for building the project.  Because I needed access to shadow (https://github.com/johnrengelman/shadow) to make this happen.  shadowjar task builds this almost like magic.

More useful URLS:
https://stackoverflow.com/questions/53533486/how-to-open-javafx-jar-file-with-jdk-11?noredirect=1    JAR fat vs nonfat
javafxports/openjdk-jfx#236 (comment)    Why need Launcher class?


Below is the build.gradle I used and my build project structure

GradeAnalyzer
   | .gradle
   | .idea
   | build
   | gradle
   | src
   |   | main
   |   |   | java
   |   |   |   | Controller.java
   |   |   |   | GradeAnalyzer.java
   |   |   |   | GUI.java
   |   |   |   | Launcher.java
   |   |   | resources
   |   |   |   | GUI.fxml
   |   | test
   | build.gradle
   | gradlew
   | gradlew.sh
   | settings.gradle


buildscript {
    repositories {
        jcenter()
        flatDir dirs: "/home/thomas/Downloads/javafx-sdk-14/lib/"
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
        classpath files("/home/thomas/Downloads/javafx-sdk-14/lib/javafx.controls.jar")
        classpath files("/home/thomas/Downloads/javafx-sdk-14/lib/javafx.fxml.jar")
    }
}


plugins {
    id 'java'
}
plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'


group 'com.utopple.code'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8



repositories {
    mavenCentral()
}

javafx {
    version = "13"
    modules = [ 'javafx.controls' , 'javafx.fxml']
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

mainClassName = 'Launcher'
torkus pushed a commit to torkus/clojure-javafx that referenced this issue Jun 9, 2020
favu100 pushed a commit to hhu-stups/prob2_ui that referenced this issue Jul 10, 2020
Our main class is not a JavaFX application class, because of our
workaround for OpenJFX normally needing to be a module:
javafxports/openjdk-jfx#236

This fixes an error about missing JavaFX runtime components when
running the shadow jar with Java 14.
@davidfrancisandroidemul

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!

@nlisker
Copy link

nlisker commented Jul 27, 2020 via email

@nlisker
Copy link

nlisker commented Jul 27, 2020

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

@connorsadler
Copy link

connorsadler commented Jul 27, 2020

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?

@nlisker
Copy link

nlisker commented Jul 27, 2020

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.

ra4king added a commit to ra4king/CircuitSim that referenced this issue Aug 23, 2020
…ld file setup by arcostasi in #66:

- Move all source code to src/main/java
- Move all images to src/main/resources/images
- Move all fonts to src/main/resources/fonts
- Move main method to CircuitSimRunner since the main class cannot extend Application to be able to run the jar: javafxports/openjdk-jfx#236
ghubstan added a commit to ghubstan/bisq2 that referenced this issue Jun 4, 2021
The generated jfx distribution requires a wrapper around
JfxMain.  Main must be the dist's entry point.  Renaming
JfxMain as Main does not fix the dist runtime problem.

See javafxports/openjdk-jfx#236
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants