{"id":23156993,"url":"https://github.com/bradh/jpackagedemo","last_synced_at":"2025-04-04T17:44:28.723Z","repository":{"id":145516507,"uuid":"538909689","full_name":"bradh/jpackagedemo","owner":"bradh","description":null,"archived":false,"fork":false,"pushed_at":"2022-09-20T09:33:43.000Z","size":604,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-17T03:53:53.818Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bradh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-20T09:33:41.000Z","updated_at":"2022-09-20T09:33:48.000Z","dependencies_parsed_at":"2023-04-04T21:33:32.619Z","dependency_job_id":null,"html_url":"https://github.com/bradh/jpackagedemo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":"dlemmermann/JPackageScriptFX","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradh%2Fjpackagedemo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradh%2Fjpackagedemo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradh%2Fjpackagedemo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradh%2Fjpackagedemo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bradh","download_url":"https://codeload.github.com/bradh/jpackagedemo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226196,"owners_count":20904464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-17T21:16:05.096Z","updated_at":"2025-04-04T17:44:28.715Z","avatar_url":"https://github.com/bradh.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JPackageScriptFX #\n\n\u003ca href=\"https://foojay.io/today/works-with-openjdk\"\u003e\u003cimg align=\"right\" src=\"https://github.com/foojayio/badges/raw/main/works_with_openjdk/Works-with-OpenJDK.png\" width=\"100\"\u003e\u003c/a\u003e\n\nThis project demonstrates how projects can use scripts to build self-contained, platform-specific executables and \ninstallers of their JavaFX applications via the `jdeps`, `jlink`, and `jpackage` tools. Two scripts are included for \nrunning builds on Mac/Linux and Windows. The `jpackage` tool is bundled with the JDK since version 14.\n\nImportant: the scripts do not try to create a fully modularized solution but instead try to enable existing\nprojects / applications, which often use non-modularized 3rd party dependencies, to be packaged again after the\nprevious packaging tool stopped working since Java 11.\n\n### Prerequisites\n\n* Any OpenJDK 17 Installation ([download from AdoptOpenJDK](https://adoptopenjdk.net)) \n* On Windows you need to have the WIX toolset installed (https://wixtoolset.org)\n\n### Environment\n\nBoth platform-specific build scripts need to know where they can find the java installation with the jpackage tool.\nTherefore you have to set the environment variable `JAVA_HOME`. How you set it depends\non your operating system. On Mac/Linux you can set it inside the .bash_profiles file in your user home directory. On Windows\nyou would set it in the \"environment variables\" dialog. In your IDE you can normally also set it as part of a\nMaven run configuration. If you are the only one working on the project then you can even add it to the pom.xml file of\nthe main module. \n\n### Project Structure\n\nThe project in this repository uses a multi-module Maven setup with a parent module containing three child modules.\nOne of these child modules is the \"main\" module as it contains the main class. This module also contains the build\nscripts and its target directory will contain the results of the build. The JavaFX application consists of a single\nwindow displaying three labels. The first one shows the currently configured locale and the other two labels get\nimported from module 1 and module 2 respectively.\n\n![alt text](app.png \"Demo App\")\n\n### Launcher Class\n\nUpon closer inspection you will notice that the scripts are not creating packages and executables for `App` (which \nextends the standard JavaFX `Application` class) but for `AppLauncher`. When an `Application` class gets launched then \nJavaFX will check whether the JavaFX modules are present on the module path. But since we are placing them on the \nclasspath the application can not launch. As a work-around we are starting a standard Java class with a main method in \nit. This prevents the module path check and the application will launch just fine without us having to provide any of\nthe module system specific options.\n\n### Icons\n\nExecutables require an application icon. Default icons are part of the project. Feel free to use it for your \ndevelopment efforts but make sure to replace it with your own before shipping your product. The platform-specific\nicons can be found inside `jpackagefx-main/src/main/logo`.\n\n### Building the Project\n\nOnce your environment is set up you can simply call the `mvn clean install` on the root / parent module. It will do\na standard build of the application and in addition it will analyze all the dependencies and copy the resulting set of\nJAR files into the folder target/libs. This work is done via the Maven dependency plugin. Once the standard build is \ncompleted Maven will invoke the shell script (on Mac/Linux) or the batch script (on Windows). The Maven  main-ui/pom.xml uses two \ndifferent profiles, both of them being activated via the OS that they are running on.\n\nThe scripts both have the same structure:\n* Environment\n* Dependency Analysis\n* Runtime Image Generation\n* Packaging\n\n### Environment\n\nThe required environment for the scripts consists of environment variables and a directory structure. The following\nvariables are used:\n\n* JAVA_HOME - the location of the JDK matching the Java version\n* JAVA_VERSION - defines the runtime environment that the final application is targeting\n* PROJECT_VERSION - the version of the project as defined in the pom.xml file (e.g. 1.0-SNAPSHOT)\n* APP_VERSION - the version for the executable (careful: do not re-use project version. The supported Windows version \n  number format has to be major.minor.build, e.g. 1.0.2412. Mac seems to be more flexible.)\n* MAIN_JAR - the name of the jar file that contains the main class\n  \nThe directory structure required by the build:\n\n* `target/java-runtime` - contains the runtime environment generated by jlink as part of the build\n* `target/installer` - contains the executables generated by jpackage as part of the build\n* `target/installer/input/libs` - contains the jars required by the application to run\n \n### Dependency Analysis\n\nThe scripts use the `jdeps` tool to analyze the dependencies of the application to determine which modules need to\nbe included in the final package. These modules are stored in the list `detected_modules`. \n\n```bash\ndetected_modules=$JAVA_HOME/bin/jdeps\n  --multi-release ${JAVA_VERSION}\n  --ignore-missing-deps\n  --print-module-deps\n  --class-path \"target/installer/input/libs/*\"\n    target/classes/com/dlsc/jpackagefx/App.class\n```\n\nHowever, the tool can not always find all modules via this static analysis. E.g., when they are only \nneeded to provide a specific service implementation, some manual intervention is required. For this you can add modules \nto the comma-separated list called `manual_modules`.\n\nIf your application is localized you should also always add `jdk.localedata` to this list.\nThis can be reduced to the actually needed locales via a jlink paramter later, e.g., `--include-locales=en,de`.\n\n```bash\nmanual_modules=,jdk.crypto.ec,jdk.localedata\n```\n\n### Runtime Image Generation\n\nThe next tool to call is called `jlink`. It generates a java runtime environment for our application and places its content\ninside the folder target/java-runtime. We could have relied on `jpackage` to perform the linking for us but unfortunately\nit does not behave very well with automatic modules, yet. So in order to have full control over the image generation we\nare letting the script do it via `jlink`.\n\n```bash\n$JAVA_HOME/bin/jlink\n  --no-header-files\n  --no-man-pages \n  --compress=2 \n  --strip-debug\n  --add-modules \"${detected_modules}${manual_modules}\"\n  --include-locales=en,de\n  --output target/java-runtime\n```\n    \nIn our example code whe have added the module `jdk.crypto.ec`, which would be needed to make https-requests.\nBut this is just an example here because the code does not actually make use of it.\n\nIf you want to stay on the safe side or if you experience strange errors, which might be due to some missing\nservice providers, you can add the option `--bind-services` to the `jlink` command.\nThis will, however, make the resulting image much bigger because it will include all service implementations\nand not just the ones that you actually need.\n\nThe `jlink` command has an option `--suggest-providers` which, without any further parameters, just outputs a list\nof all service providers on the module path (by default the whole JDK), but that list is far too long and unspecific to be really useful.\nIn a variant of this option you can explicitly specify a service interface and you will get a list of all implementors\nof this interface but that implies that you have to know all relevant service interfaces which are possibly used deep down\nin your dependencies or the JDK. So, at the moment this remains a try-and-error game.\n    \n### Packaging\n\n#### Basics\n\nFinally we are invoking the `jpackage` tool in a loop so that it generates all available package types for the platform\nthat the build is running on. Please be aware that `jpackage` can not build cross-platform installers. The build has to\nrun separately on all platforms that you want to support. When the build is done you will find the installers inside\nthe directory `target/installer`. On Mac you will find a DMG, PKG, or an APP. On Linux a DEB, RPM or an application directory.\nOn Windows you will find an application directory, an EXE, and an MSI. Please be aware that the EXE is not the application\nitself but an installer.\n\n```bash\nfor type in \"app-image\" \"dmg\" \"pkg\"\ndo\n  $JPACKAGE_HOME/bin/jpackage\n  --package-type $type\n  --dest target/installer\n  --input target/installer/input/libs\n  --name JPackageScriptFX\n  --main-class com.dlsc.jpackagefx.AppLauncher\n  --main-jar ${MAIN_JAR}\n  --java-options -Xmx2048m\n  --runtime-image target/java-runtime\n  --icon src/main/logo/macosx/duke.icns\n  --app-version ${APP_VERSION}\n  --vendor \"ACME Inc.\"\n  --copyright \"Copyright © 2019-21 ACME Inc.\"\n  --mac-package-identifier com.acme.app\n  --mac-package-name ACME\ndone\n```\n\n#### Customization\n\nOnce you have come this far, you can now consider to customize your packaging.\nUnder the hood the `jpackage` tool uses platform-specific tooling to create the various package types.\nThe customization of the packaging is therefore also very platform-specific and has to be individually\nfor each supported platform and package type. However, there are two common features of `jpackage` that you can use to make this task easier.\n\nThe first one is the option `--temp some_temp_dir` which asks `jpackage` to copy all scripts and resources needed to create the selected package type into a directory `some_temp_dir`. These are the scripts and resources that `jpackage` would use by default.\n\nThe second one is the option `--resource-dir some_resource_dir` which asks `jpackage` to first look\nfor resources in the directory `some_resource_dir` and then use its defaults only for the ones it does not find there.\n\nWith these two options you can first generate a set of default resources from which you can pick the ones you want to modify and copy them over to the directory `some_resource_dir`. In a second run of\n`jpackage` you can then apply these changes. The most likely changes you can make this way is to exchange\nthe default icons, used by the various package types, with your own ones.\n\nWe do not yet provide an example for these customizations because this is still work in progress and there are\nstill some problems.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradh%2Fjpackagedemo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbradh%2Fjpackagedemo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradh%2Fjpackagedemo/lists"}