# JavaFX 14 Projekt als EXE (ich verzweifle)



## benearth (9. Jun 2020)

Hallo liebe leute,
Seit mehr als zwei Tagen versuche ich zu Lernen wie ich es schaffe mein Java Projekt wia exe datei auf meinem Rechner zu speichern. 
Ja ich habe gegoogelt, wirklich und nicht wenig, ich habe mir alles durch gelesen. jpackager, maven ,gradle und was es alles gibt. 
Ich hab zich stackoverflow Einträge und Internet seiten zu dem Thema durch gelesen und viele auch Probiert. 
Auch habe ich viel gelesen IntelliJ seit dabei einfacher wie Eclipse, doch auch dort klappt es nicht. Entweder bin ich einfach zu dumm oder es hapert an meinem englisch obwohl ich nicht sagen würde das es schlecht ist.
Vielleicht findet sich ja jemand der einem in die Jahre gekommen Java einsteiger erklären kann wie ich das hin bekomme. 
Oder jemand hat ne gute Internet Seite am liebsten auf deutsch die einem das step bei step erklärt.
Was mich am meisten verwirrt ist das es scheinbar soooo viele verschiedene Wege gibt, manche Erklärungen sind zwei Zeilen lang, manche sind 4 seiten lang.

Bitte verzeiht mir wenn ich keine Fehler oder sonst etwas in der Richtung Poste. Ich versuche das erste mal so etwas und lerne Java jetzt seit 5 Monaten. Ich weiß also nicht genau was ich genau posten kann um euch zu helfen. Wenn ihr mir sagt was gebraucht wird schicke ich euch das.


----------



## mihe7 (9. Jun 2020)

benearth hat gesagt.:


> Seit mehr als zwei Tagen versuche ich zu Lernen wie ich es schaffe mein Java Projekt wia exe datei auf meinem Rechner zu speichern.


Normalerweise macht man ein Jar draus und gibt das weiter  Auf dem Rechner muss dann ein Java Runtime Environment (JRE) vorhanden sein oder mit ausgeliefert werden. Mit jlink kannst Du seit Java 9 Dein Programm auch zusammen mit einem maßgeschneiderten JRE ausliefern. Dabei erstellt jlink auf Wunsch auch einen Launcher (weiß aber nicht, ob das unter Windows eine EXE oder ein Shell-Skript ist). Mit jpackage (ab Java 14) kann man wohl auch native Installer (unter Windows MSI-Pakete) erzeugen - selbst nicht getestet.

Das sind die Bordmittel, die mir ad hoc einfallen. Ansonsten gibt es noch Schweinereien, die einen EXE-Launcher (das ist aber nur ein Launcher) erstellen. Kann auch sein, dass es noch andere Werkzeuge gibt, die ein all-in-one EXE generieren, das entzieht sich jedoch meiner Kenntnis. Außerdem gibt es immer die Möglichkeit, einen Installer zu verwenden.

Ist halt die Frage, was Du nun vor hast


----------



## benearth (9. Jun 2020)

mihe7 hat gesagt.:


> Normalerweise macht man ein Jar draus und gibt das weiter  Auf dem Rechner muss dann ein Java Runtime Environment (JRE) vorhanden sein


das mit der Jar klappt bei mir seit dem ich Java14 nutze nicht mehr.


mihe7 hat gesagt.:


> Mit jpackage (ab Java 14) kann man wohl auch native Installer (unter Windows MSI-Pakete) erzeugen - selbst nicht getestet.


genau das wäre mega wenn sich jemand findet der das nuzt und mit erklären könnte wie ich das nutze mit javafx


mihe7 hat gesagt.:


> Ist halt die Frage, was Du nun vor hast


ich möchte mein Programm bei mir aufn Rechner installieren und nutzen.


----------



## M.L. (9. Jun 2020)

> ...jpackage...erklären könnte wie ich das nutze mit javafx


Zwar auf englisch, aber trotzdem: https://blogs.oracle.com/jtc/a-brief-example-using-the-early-access-jpackage-utility


----------



## mihe7 (9. Jun 2020)

Oder https://www.baeldung.com/java14-jpackage


----------



## benearth (9. Jun 2020)

M.L. hat gesagt.:


> Zwar auf englisch, aber trotzdem: https://blogs.oracle.com/jtc/a-brief-example-using-the-early-access-jpackage-utility


kenn ich 


mihe7 hat gesagt.:


> Oder https://www.baeldung.com/java14-jpackage


kenn ich auch 

entweder habe ich mich zu viel damit beschäftigt und habe mich selber fest gelesen. Wisst ihr was ich meine, wie mit dem Wald und den Bäumen. Oder ich verstehe etwas elementares nicht. es muss ja nicht unbedingt jpackage sein. mir würde einfach ein weg helfen aus meiner jar ein lauffähiges Programm zu machen. Und vielleicht ganz vielleicht erklärt sich sogar jemand bereit mir das im discord näher zu bringen.


----------



## sascha-sphw (10. Jun 2020)

Woran genau scheitert es denn? Ich hatte das zuvor mit jpackr gemacht und muss sagen seit ich jpackage verwende habe ich weit weniger Probleme.


----------



## sascha-sphw (10. Jun 2020)

So, ich habe jetzt mal was vorbereitet, da ich selber ein wenig damit zu kämpfen hatte.

*1. Erstelle ein Maven Projekt*

Struktur

```
jfx-sample-app
    - src
        - main
            - java
                - de.sphw.samples
                    - App.java
                    - AppStarter.java
    - build-installer.bat
    - pom.xml
```



Spoiler: pom.xml





```
<?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>de.sphw.samples</groupId>
  <artifactId>jfx-sample-app</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>jfx-sample-app</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>14</maven.compiler.source>
    <maven.compiler.target>14</maven.compiler.target>
  </properties>

  <dependencies>

    <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
    <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-controls</artifactId>
      <version>14.0.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-graphics -->
    <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-graphics</artifactId>
      <version>14.0.1</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>14</release>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.1</version>
        <configuration>
          <finalName>${project.name}</finalName>
          <archive>
            <manifest>
              <mainClass>de.sphw.samples.AppStarter</mainClass>
              <addClasspath>true</addClasspath>
              <classpathPrefix>lib/</classpathPrefix>
              <useUniqueVersions>false</useUniqueVersions>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <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}/lib</outputDirectory>
              <overWriteReleases>false</overWriteReleases>
              <overWriteSnapshots>false</overWriteSnapshots>
              <overWriteIfNewer>true</overWriteIfNewer>
              <includeScope>compile</includeScope>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>
```






Spoiler: de.sphw.samples.App.java





```
package de.sphw.samples;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

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

    public void start(Stage stage) {
        VBox rootNode = new VBox();
        rootNode.setAlignment(Pos.CENTER);

        Button clickMe = new Button("Click Me!");
        clickMe.setOnAction(actionEvent -> {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("Important information");
            alert.setHeaderText("It works...");
            alert.setContentText("... like a charm!");
            alert.show();
        });
        rootNode.getChildren().add(clickMe);

        Scene scene = new Scene(rootNode);
        stage.setTitle("Sample FX App");
        stage.setWidth(300);
        stage.setHeight(150);
        stage.setScene(scene);
        stage.show();
    }
}
```






Spoiler: de.sphw.samples.AppStarter.java





```
package de.sphw.samples;

public class AppStarter {
    public static void main(String[] args) {
        App app = new App();
        app.start(args);
    }
}
```




*2. Lade und installiere https://wixtoolset.org

3. Baue die Applikation*


```
mvn clean package
```

Die zwei plugins im pom sorgen zum einen für die Erstellung des Manifests und das Kopieren aller dependencies in den lib folder (den brauchen wir später).

*4. Vorbereitung für jpackage*

Packe den lib folder und die jar in einen Ordner "input". Der Name ist nicht relevant, aber alles was in diesem Ordner ist, wird in den Installer gepackt.

*5. Baue eine custom jre*

Es geht auch ohne diesen Schritt, aber dann ist das jre das mit rein gepackt wird um einiges größer.

```
jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.desktop,java.xml,jdk.unsupported --output ./target/custom_jre
```


Wenn Du nicht weißt, welche Module Du genau mit rein packen musst, kannst Du das mit jdep heraus finden. Die module hier sind die dependencies Deiner Applikation, die sind ggf. auch auf jre module angewiesen.

```
jdeps --module-path ./target/lib --add-modules=javafx.controls,javafx.graphics --multi-release 14 --list-deps ./target/jfx-sample-app.jar
```

*6. Baue einen Installer*


```
jpackage -n "Sample FX App" --app-version "1.0.0-SNAPSHOT" -i ./target/input --main-jar ./target/jfx-sample-app.jar -t msi --runtime-image ./target/custom_jre -d target
```

*7. Packe alles in ein batch file und hör auf es manuell zu machen. :-D*



Spoiler: build-installer.bat





```
@echo off

set JAVA_HOME="<path to java home. NOT THE BIN FOLDER!>"
set MAVEN_HOME="<path to maven home. NOT THE BIN FOLDER!>"
set PATH=%PATH%;%JAVA_HOME%\bin;%MAVEN_HOME%\bin

REM build the project
echo "build mvn"
call mvn clean package

REM copy lib folder and jar
echo "copy target"
xcopy .\target\lib .\target\input\lib /S/C/I
xcopy .\target\jfx-sample-app.jar .\target\input\jfx-sample-app.jar*

REM custom jre
echo "create custom jre"
jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.desktop,java.xml,jdk.unsupported --output ./target/custom_jre

REM build installer
echo "package"
jpackage -n "Sample FX App" --app-version "1.0.0" -i ./target/input --main-jar jfx-sample-app.jar -t msi --runtime-image ./target/custom_jre -d target
```




Sag bescheid ob das hilft.


----------



## benearth (11. Jun 2020)

uff ich danke danke danke dir für deine mühe. ich werde es morgen direkt mal testen wenn das klappt lad ich dich aufn Bier ein oder Getränk/e deiner Wahl.
kurze zwischen fragen bevor ich es versuche
was ist ein Bash das ist doch ein file das ich starten kann um befehle in der Konsole auszuführen oder??
p.s.: es beruhigt mich sowas von das ich nicht der einzige bin der damit Probleme hat


----------



## mihe7 (11. Jun 2020)

benearth hat gesagt.:


> wenn das klappt lad ich dich aufn Bier ein oder Getränk/e deiner Wahl.


@sascha-sphw die Magnum-Flasche Schampus ist gesichert 



benearth hat gesagt.:


> was ist ein Bash das ist doch ein file das ich starten kann um befehle in der Konsole auszuführen oder??


Bash ist eine Shell (wie die Eingabeaufforderung unter Windows). Was Du meinst ist ein Batch-File (auch Shell-Skript genannt) - wie unter 7.


----------



## sascha-sphw (11. Jun 2020)

benearth hat gesagt.:


> uff ich danke danke danke dir für deine mühe. ich werde es morgen direkt mal testen wenn das klappt lad ich dich aufn Bier ein oder Getränk/e deiner Wahl.


Gern geschehen.

Ich habe aber noch einen Fehler gefunden, die letzte Anweisung muss so aussehen.
Der Zusatz Snapshot in der Version wird von msi nicht unterstützt und die jar muss relativ zum input Ordner sein. 

```
jpackage -n "Sample FX App" --app-version "1.0.0" -i input --main-jar jfx-sample-app.jar -t msi --runtime-image ./target/custom_jre -d target
```
Die müsstest du dann im batch file ggf. noch anpassen.

Ansonsten gerne wieder melden.



mihe7 hat gesagt.:


> @sascha-sphw die Magnum-Flasche Schampus ist gesichert


Die Gläser stehen schon auf dem Tisch.


----------



## benearth (11. Jun 2020)

bei punkt eins steck ich schon fest. maven hatte ich noch nicht gemacht der fragt nach einer artefakt id. ich habe opfenjf genommen meine Ordner Struktur schaut nun ganz anders aus wie bei dir ist das ein Problem?


----------



## benearth (11. Jun 2020)

```
<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>JavaFx</groupId>
    <artifactId>de.benearth.JavaFx</artifactId>
    <version>0.0.1</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>14</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>14</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.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.4</version>
                <configuration>
                    <mainClass>JavaFx.de.benearth.JavaFx.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```


----------



## M.L. (11. Jun 2020)

benearth hat gesagt.:


> ist das ein Problem?


 Nicht zwingend, aber um ein ständiges Umdenken zu vermeiden  setzt man besser ein neues Projekt auf und verwendet die Parameter, die unter dem Button "Spoiler: pom.xml" zu sehen sind.


----------



## sascha-sphw (12. Jun 2020)

benearth hat gesagt.:


> bei punkt eins steck ich schon fest. maven hatte ich noch nicht gemacht der fragt nach einer artefakt id. ich habe opfenjf genommen meine Ordner Struktur schaut nun ganz anders aus wie bei dir ist das ein Problem?



Man kann es auch mit Gradle machen, für mich gab es aber noch keinen Grund mein Build System zu wechseln. Wenn Du beides noch nicht kennst wäre es sicher nicht schlecht, sich in diese Systeme einzulesen.

Hier mal ein Maven getting started: https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html

Damit Du aber vorwärts kommst..., mit dem folgendem Maven Befehl kannst Du Dir schnell das Grundkonstrukt erstellen lassen.

```
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=RELEASE -DgroupId=de.sphw.samples -DartifactId=jfx-sample-app -Dversion=1.0-SNAPSHOT
```

Ich nehme ganz gerne das quickstart template, es gibt auch welche direkt für JavaFx. Ich mache das aber lieber so, da ich die Versionen der dependencies ohnehin meistens anpassen muss.

Maven archetypes sind nichts anderes als Projekt Templates, mit deren Hilfe Du schnell eine Projektstruktur anlegen kannst ggf. mit vordefinierten Plugins und Dependencies in der pom.xml, oder sogar Projekt Ressourcen. Hier im Befehl braucht maven die Version des Templates das Du verwenden möchtest.

```
-DarchetypeGroupId
-DarchetypeArtifactId
-DarchetypeVersion
```

Das gleiche braucht Maven auch für das Projekt das Du erstellen möchtest.

```
-DgroupId
-DarifactId
-Dversion
```
 
GroupId, ArtifactId und Version sind nichts anderes als Koordinaten, damit Maven eindeutig identifizieren kann um was es sich handelt.

Was die einzelnen Parameter bedeuten kannst Du hier nachlesen. https://maven.apache.org/guides/getting-started/#how-do-i-make-my-first-maven-project 
BTW: Der Befehl zum erstellen eines einfachen Projekts in diesem Link hat bei mir nicht funktioniert. :-(


----------

