Übungsaufgaben zum Paketieren mit jlink und jpackage
https://bildung.social/@oerinformatik/
https://oer-informatik.de/javafx-paketieren-jpackage-uebungsaufgaben
jlink, jpackage, Laufzeitabbild, Installationspaket, MSI, DEB, Pipeline-Artefakt, GitLab CI, Gradle, Mitfahrgesuche, Übungsaufgaben, Prüfungsvorbereitung
tl/dr; (ca. 46 min Lese- und Bearbeitungszeit): Übungsaufgaben zum Paketieren der Desktop-App des Mitfahrlabors: Begriffe rund um Laufzeitabbild und Installer zuordnen, die Build-Konfiguration für die Gesuche-App ergänzen, einen Pipeline-Job schreiben, der das Paket als Artefakt ablegt, und Paketierungsfehler anhand ihrer Symptome beheben [AI-Assisted]. (Zuletzt geändert am 11.11.2026)
Diese Übungsaufgaben sind Teil einer Artikelreihe über eine Desktop-App mit JavaFX: Übersicht / Kanban-Projektstart / Projekt anlegen / FXML, Layouts und CSS / Properties, Bindings und MVVM / Backend anbinden / TableView für Buchungen / Formulare und Dialoge / Anmeldung mit Keycloak / Verwaltung und Diagramme / GUI-Tests mit TestFX / Abnahmetest und Kanban-Metriken / Paketieren mit jpackage
Diese Übungsaufgaben gehören zum Artikel Paketieren mit jlink und jpackage. Sie führen den Übungsstrang Mitfahrgesuche im Mitfahrlabor fort: Das Übungsteam hat die Gesuche-Ansicht als eigene App MitfahrgesucheApp gebaut und abgenommen. Mit dem Ticket JFX-44 „Gesuche-App als Paket“ soll sie nun als Installationspaket zu den Fahrer*innen kommen. Startcode für die Aufgaben 2.1 und 2.2 ist der Ordner src/11-abnahmetest-kanban-metriken/uebung-mitfahrgesuche; die Beispiellösung liegt im Ordner src/12-paketieren-jpackage/uebung-mitfahrgesuche (Gradle, Maven-Profil paket, .gitlab-ci.yml, Ordner jpackage).
Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1. Als FIA, FIDP oder FIDV musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das sind Aufgabe 2.1 und Aufgabe 2.2. Von FIA wird zusätzlich erwartet, dass ihnen Aufgaben auf Profilkompetenz-Ebene (Aufgabe 3.1) keine Probleme bereiten. Zum Bauen brauchst Du ein JDK 25 mit jlink und jpackage; für ein MSI zusätzlich Windows mit WiX Toolset, für ein DEB Linux mit fakeroot. Ohne diese Werkzeuge lässt sich jede Aufgabe mit -Ptyp=app-image prüfen. Schreib Deine Lösung zuerst vollständig auf, bevor Du die Beispiellösung aufklappst.
Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?
Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.
Erstelle neue Übungsaufgaben zum Thema „Paketieren mit jlink und
jpackage“.
Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.
Fachliche Grundlage:
- https://oer-informatik.de/javafx-paketieren-jpackage
- https://oer-informatik.de/szenario-mitfahrlabor
- Stilbeispiel: https://oer-informatik.de/javafx-paketieren-jpackage-uebungsaufgaben
Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- jlink
- jpackage
- Laufzeitabbild
- Installationspaket
- MSI
- DEB
- Pipeline-Artefakt
- GitLab CI
- Gradle
- Mitfahrgesuche
Kompetenzstufe: Kernkompetenz (alternativ: Basiskompetenz, Profilkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan
Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
danach frage.
Aufgabe 1.1: Begriffe rund ums Paketieren (Basiskompetenz)
Im Kanban-Meeting erklärt das Übungsteam einer neuen Person, was beim Ticket JFX-44 passiert. Dabei fallen die folgenden Beschreibungen:
| Kennbuchstabe | Beschreibung |
|---|---|
| A | Ordner mit einem Startprogramm und dem eigenen Java der App; lässt sich zippen, wird aber nicht installiert. |
| B | Textdatei mit einer Option je Zeile, die jpackage mit @name einliest. |
| C | Ordner wie ein JDK, der nur die Module enthält, die die App braucht, und die App selbst. |
| D | JAR ohne module-info.class auf dem Modulpfad; Java kann es ausführen, jlink nicht einbinden. |
| E | Paket im Format des Betriebssystems, das die App in den Programmordner legt und im Startmenü einträgt. |
| F | Ordner, in dem das eigene JAR und alle Laufzeit-Abhängigkeiten für jlink zusammenliegen. |
Ordne jedem Begriff die passende Beschreibung A bis F zu: Laufzeitabbild, App-Image, Installer, Modulpfad, automatisches Modul, Argumentdatei. (6 Punkte)
Entscheide, ob die Aussage richtig oder falsch ist, und begründe in einem Satz. (4 Punkte)
- „Der Linux-Runner kann das MSI für die Rechner der Fahrer*innen gleich mitbauen.“
- „Das Laufzeitabbild enthält immer alle Module des JDK, sonst würde die App nicht starten.“
- „Wenn wir die Upgrade-UUID bei jedem Bau neu erzeugen, steht nach einem Update die App zweimal im Startmenü.“
- „jpackage signiert das MSI, damit Windows nicht warnt.“
- je Zuordnung 1 Punkt:
| Begriff | Beschreibung |
|---|---|
| Laufzeitabbild | C |
| App-Image | A |
| Installer | E |
| Modulpfad | F |
| automatisches Modul | D |
| Argumentdatei | B |
- je Aussage 1 Punkt (Entscheidung und Begründung):
- Falsch: jpackage baut nur für das Betriebssystem, auf dem es läuft; ein MSI braucht einen Windows-Runner mit WiX.
- Falsch: jlink nimmt nur die Wurzelmodule aus
--add-modulesund alles, was sie überrequiresbrauchen; Module, die über Services geladen werden (z. B.jdk.localedata), muss man selbst angeben. - Richtig: Ohne gleichbleibende Upgrade-UUID hält Windows die neue Version für eine andere Anwendung und installiert sie daneben.
- Falsch: Unter Windows signiert jpackage nicht; signiert wird danach mit Code-Signing-Zertifikat und
signtool.
Aufgabe 2.1: Build-Konfiguration für die Gesuche-App ergänzen (Kernkompetenz)
Das Übungsteam übernimmt die drei Gradle-Aufgaben aus dem Artikel in build.gradle.kts der Gesuche-App. Die App startet über die Klasse de.dbh.mitfahrlabor.desktop.MitfahrgesucheApp im Modul de.dbh.mitfahrlabor.desktop. Das Startskript im Laufzeitabbild soll mitfahrgesuche heißen, das Paket „Mitfahrgesuche“. Der Kalender im Gesuch-Dialog soll deutsche Monats- und Tagesnamen zeigen. Im Entwurf fehlen sieben Stellen:
version = (1)
// ... wie bisher, dazu windows, endung, jdkBin wie im Artikel
val hauptmodul = "de.dbh.mitfahrlabor.desktop"
val hauptklasse = "de.dbh.mitfahrlabor.desktop.MitfahrgesucheApp"
val modulpfad by tasks.registering(Sync::class) {
from(tasks.jar)
from( (2) )
into(layout.buildDirectory.dir("modulpfad"))
}
val laufzeitabbild by tasks.registering(Exec::class) {
dependsOn(modulpfad)
val ziel = layout.buildDirectory.dir("laufzeitabbild").get().asFile
outputs.dir(ziel)
doFirst { delete(ziel) }
executable = jdkBin.get().file("jlink$endung").asFile.path
args(
"--module-path", layout.buildDirectory.dir("modulpfad").get().asFile.path,
"--add-modules", (3),
"--include-locales", "de,en",
"--launcher", (4),
"--strip-debug", "--compress", "zip-6", "--no-header-files", "--no-man-pages",
"--output", ziel.path,
)
}
val installer by tasks.registering(Exec::class) {
dependsOn(laufzeitabbild)
val typ = providers.gradleProperty("typ").getOrElse(if (windows) "msi" else "deb")
val ziel = layout.buildDirectory.dir("installer").get().asFile
outputs.dir(ziel)
doFirst { delete(ziel) }
executable = jdkBin.get().file("jpackage$endung").asFile.path
args(
"--type", typ,
"--name", "Mitfahrgesuche",
"--app-version", project.version.toString(),
(5),
(6),
"--java-options", "--enable-native-access=javafx.graphics",
"--dest", ziel.path,
)
if (typ != "app-image") {
(7)
}
}Gib für die Lücken (1) bis (7) den Code an. (7 Punkte)
Erstelle die Argumentdatei
jpackage/linux.txtfür die Gesuche-App: Eintrag im Programmmenü in der Kategorie „Office“, Paketnamemitfahrgesuche. (2 Punkte)Gib die Befehle an, mit denen Du ohne WiX bzw.
fakerootprüfst, dass das Laufzeitabbild die deutschen Sprachdaten enthält und die App aus dem Paket startet. (3 Punkte)Erläutere, warum die Aufgaben
laufzeitabbildundinstallerihren Zielordner indoFirstlöschen. (2 Punkte)
- je Lücke 1 Punkt:
| Lücke | Code |
|---|---|
| (1) | "1.0.0" (nur Zahlen; -SNAPSHOT lehnt jpackage für MSI ab) |
| (2) | configurations.runtimeClasspath |
| (3) | "$hauptmodul,jdk.localedata" |
| (4) | "mitfahrgesuche=$hauptmodul/$hauptklasse" |
| (5) | "--runtime-image", layout.buildDirectory.dir("laufzeitabbild").get().asFile.path |
| (6) | "--module", "$hauptmodul/$hauptklasse" |
| (7) | args("@" + file(if (windows) "jpackage/windows.txt" else "jpackage/linux.txt").path) |
Eine Lösung, die --vendor oder --description zusätzlich setzt, ist ebenfalls richtig. Statt (5) ist auch --module-path mit dem Modulpfad möglich; dann ruft jpackage jlink selbst auf und jdk.localedata muss mit --add-modules an jpackage gehen. Das Ergebnis liegt im Ordner src/12-paketieren-jpackage/uebung-mitfahrgesuche.
- 2 Punkte (je Menü-Zeile ein halber Punkt, Paketname 1 Punkt):
--linux-shortcut
--linux-menu-group Office
--linux-package-name mitfahrgesuche
- 3 Punkte:
./gradlew installer -Ptyp=app-image # Programmordner ohne Installer
build/laufzeitabbild/bin/java --list-modules # muss jdk.localedata enthalten
build/installer/Mitfahrgesuche/bin/Mitfahrgesuche # Windows: build\installer\Mitfahrgesuche\Mitfahrgesuche.exeDanach im Gesuch-Dialog den Kalender öffnen: Er muss deutsche Monats- und Tagesnamen zeigen.
- 2 Punkte: jlink bricht ab, wenn der Ausgabeordner schon existiert; ohne Löschen würde jeder zweite Bau scheitern (1 Punkt). Beim Installer verhindert das Löschen, dass alte Pakete einer früheren Version im Ordner liegen bleiben und von der Pipeline mit eingesammelt werden (1 Punkt).
Aufgabe 2.2: Pipeline-Job für das Paket schreiben (Kernkompetenz)
Das zweite Akzeptanzkriterium von JFX-44 lautet: „Angenommen, die Pipeline läuft auf dem Hauptzweig, dann liegt das Linux-Paket der Gesuche-App danach zum Herunterladen bereit.“ Die Pipeline der Gesuche-App hat bisher nur die Stufe test mit dem Job test. Für den neuen Job gilt:
- Er läuft nur auf dem Hauptzweig und nur, wenn der Job
testgrün war. - Das Image
eclipse-temurin:25-jdkbringtdpkg-debmit,fakerootfehlt. - Die Gesuche-App soll das Backend unter
http://mitfahrlabor.schule.example/v1erreichen. - Das Artefakt heißt
mitfahrgesuche-plus kurze Commit-Kennung und wird 14 Tage aufbewahrt.
Schreibe die Ergänzungen der
.gitlab-ci.yml: neue Stufe und Jobgesuche-deb. (7 Punkte)Begründe, warum derselbe Job kein MSI für Windows-Rechner bauen kann, und beschreibe, was für ein MSI-Job nötig ist. (2 Punkte)
Nach dem ersten Lauf ist der Job grün, auf der Pipeline-Seite gibt es aber kein Paket zum Herunterladen. Nenne die wahrscheinliche Ursache und wo Du sie im Job-Log erkennst. (2 Punkte)
- 7 Punkte: Stufe
paket(1),needs(1),rulesfür den Hauptzweig (1),fakerootinstallieren (1), Aufruf mit Typ und Adresse (1), Artefakt-Pfad passend zu--dest(1), Name und Aufbewahrung (1).
stages:
- test
- paket
gesuche-deb:
stage: paket
needs: [test]
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- apt-get update && apt-get install -y --no-install-recommends fakeroot
- chmod +x gradlew
- ./gradlew installer -Ptyp=deb -Papi=http://mitfahrlabor.schule.example/v1 --no-daemon
artifacts:
name: "mitfahrgesuche-$CI_COMMIT_SHORT_SHA"
expire_in: 14 days
paths:
- build/installer/*.debDie Adresse wirkt nur, wenn build.gradle.kts die Eigenschaft api wie im Artikel in --java-options "-Dmitfahrlabor.api=…" übernimmt. Die vollständige Datei liegt als .gitlab-ci.yml im Ordner der Beispiellösung.
2 Punkte: jpackage baut nur für das Betriebssystem, auf dem es läuft; der Job läuft in einem Linux-Container (1 Punkt). Für ein MSI braucht es einen eigenen Job auf einem Windows-Runner (Auswahl über
tags) mit JDK 25 und WiX Toolset, dergradlew.bat installer "-Ptyp=msi"aufruft undbuild/installer/*.msials Artefakt ablegt (1 Punkt).2 Punkte: Der Pfad unter
artifacts: pathspasst nicht zum Zielordner von--dest(z. B. Tippfehler im Ordner oder in der Endung) (1 Punkt). GitLab bricht dann nicht ab, sondern schreibt beim Hochladen der Artefakte nur eine Warnung „no matching files“ ins Log (1 Punkt).
Aufgabe 3.1: Paketierungsfehler beheben (Profilkompetenz)
Das Übungsteam hat JFX-44 nach „Test“ gezogen. Thomas Becker prüft die Gesuche-App auf einem Rechner ohne Java, eine weitere Person beobachtet die Pipeline. Zusammen kommen fünf Befunde zusammen. Die Ausschnitte stammen aus dem Stand des Übungsteams und sind absichtlich fehlerhaft.
| Nr. | Symptom | Ausschnitt aus dem Stand |
|---|---|---|
| S1 | Der Job gesuche-deb ist grün, der neue MSI-Job auf dem Windows-Runner bricht mit einer Meldung zur Versionsnummer ab. |
version = "0.0.1-SNAPSHOT" |
| S2 | Der Kalender im Gesuch-Dialog der installierten App zeigt „Dec“ und englische Wochentage. Mit gradlew run ist alles deutsch. |
"--add-modules", hauptmodul, |
| S3 | gesuche-deb ist grün, aber es gibt kein Artefakt. |
paths: - build/jpackage/*.deb und in Gradle "--dest", ziel.path mit ziel = …dir("installer") |
| S4 | Auf dem Testrechner ist MITFAHRLABOR_API auf das Schul-Backend gesetzt, die App verbindet sich trotzdem mit localhost:8080. |
Aufruf im Job: ./gradlew installer -Ptyp=deb --no-daemon |
| S5 | Nach dem Update auf Version 1.0.1 steht „Mitfahrgesuche“ zweimal im Startmenü. | jpackage/windows.txt enthält nur --win-menu und --win-shortcut |
Erläutere für jedes Symptom S1 bis S5 die Ursache und gib die Korrektur an. (10 Punkte)
Die Befunde S2 und S4 sind erst beim Test auf einem fremden Rechner aufgefallen. Schlage zwei Ergänzungen für die Workflow-Definition oder die Pipeline vor, mit denen solche Fehler früher auffallen. (3 Punkte)
Eine Person schlägt vor, in der Methode
einstellung(…)der App die Rangfolge umzudrehen: erst die Umgebungsvariable, dann die Systemeigenschaft. Nimm Stellung. (3 Punkte)
- je Symptom 2 Punkte (Ursache 1, Korrektur 1):
- S1: Für MSI erlaubt Windows nur Versionsnummern aus Zahlen (Haupt-, Neben-, Build-Nummer); unter Linux nimmt jpackage
-SNAPSHOTan, deshalb ist nur der Windows-Job rot. Korrektur:version = "1.0.0"und mit jeder Auslieferung erhöhen. - S2: Die deutschen Sprachdaten stehen im Modul
jdk.localedata, das über einen Service geladen wird und deshalb nicht im Modulgraphen auftaucht; ohne es fällt Java still auf englische Formate zurück.gradlew runnutzt das vollständige JDK. Korrektur:"--add-modules", "$hauptmodul,jdk.localedata"und"--include-locales", "de,en". - S3: Der Artefakt-Pfad zeigt auf
build/jpackage, das Paket liegt inbuild/installer; GitLab warnt nur („no matching files“). Korrektur:paths: - build/installer/*.deb. - S4: Ohne
-Papi=…schreibt der Build-Dmitfahrlabor.api=http://localhost:8080/v1in die Konfigurationsdatei des Pakets. Die App liest zuerst die Systemeigenschaft, die Umgebungsvariable kommt nicht mehr zum Zug. Korrektur: im Job-Papi=http://mitfahrlabor.schule.example/v1angeben (oder die Option im Paket ganz weglassen, wenn die Adresse über die Umgebungsvariable kommen soll). - S5: Ohne feste
--win-upgrade-uuiderzeugt jpackage bei jedem Bau eine neue Kennung; Windows hält 1.0.1 für eine andere Anwendung. Korrektur: einmal eine UUID erzeugen und als--win-upgrade-uuid <uuid>dauerhaft injpackage/windows.txteintragen; die alte Version einmalig von Hand entfernen.
- 3 Punkte, zwei begründete Vorschläge (1,5 Punkte je Vorschlag), zum Beispiel:
- Regel für „Test“: Tickets mit Paket werden aus dem installierten Paket bzw. App-Image auf einem Rechner ohne JDK geprüft, nicht mit
gradlew run. - Pipeline-Schritt nach dem Paketbau:
build/laufzeitabbild/bin/java --list-modulesmussjdk.localedataenthalten, und die DateiMitfahrgesuche.cfgim App-Image wird auf die erwartete Backend-Adresse geprüft (z. B. mitgrep); ein Fehlschlag macht den Job rot. - Ein Smoke-Test, der das App-Image headless startet und den Monatsnamen im Kalender prüft.
- 3 Punkte: Für die Umkehr spricht, dass die Verwaltung die Adresse auf jedem Rechner ohne neues Paket ändern kann (1 Punkt). Dagegen spricht, dass eine vergessene oder alte Umgebungsvariable dann jede Einstellung aus dem Paket überstimmt und Fehler schwer zu finden sind; die übliche Rangfolge in Java-Anwendungen ist „Kommandozeile vor Umgebung“ (1 Punkt). Eine begründete Entscheidung, z. B.: Rangfolge lassen und keine Adresse ins Paket schreiben, wenn sie je Rechner verschieden sein soll; oder eine Konfigurationsdatei als eigenes Ticket (1 Punkt).
Links und weitere Informationen
zum Artikel: Paketieren mit jlink und jpackage: die Desktop-App als Installationspaket ausliefern
zum Übungsstrang: Übungsaufgaben zu Abnahmetest und Kanban-Metriken
als Nachschlagewerk: Oracle: jpackage – Tool Reference (JDK 25)
als Nachschlagewerk: GitLab: Job artifacts
für den Einstieg: Szenario Mitfahrlabor mit Personas und Regeln
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zum Paketieren mit jlink und jpackage” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/javafx-paketieren-jpackage-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/javafx/javafx-einstieg. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 11.11.2026.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]
