首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有JavaFX 17的Leiningen Uberjar

带有JavaFX 17的Leiningen Uberjar
EN

Stack Overflow用户
提问于 2021-10-29 14:58:35
回答 1查看 116关注 0票数 2

我有一个程序是在2014年用Clojure和JavaFX写的。程序的依赖项最近被修改为使用Java 17。简单地替换依赖项的新版本会产生一个与无法读取新的类文件格式相关的错误。我想更新应用程序,但还无法使用当前版本的Java (17)和JavaFX (17.0.1)生成uberjar。

下面是SSCCE的project.clj和源文件。

代码语言:javascript
复制
(defproject sutest "0.1.0-SNAPSHOT"
  :description "Test for including JavaFX components in uberjar"
  :dependencies [[org.clojure/clojure "1.10.3"]
                 [org.openjfx/javafx-controls "17.0.1"]]
  :aot :all
  :main sutest.core)
代码语言:javascript
复制
(ns sutest.core
  (:gen-class
    :extends javafx.application.Application)
  (:import
    [javafx.application Application Platform]
    [javafx.event EventHandler]
    [javafx.geometry Insets Pos]
    [javafx.scene Scene]
    [javafx.scene.control Button Label]
    [javafx.scene.layout VBox]))

(defn -start [this stage]
  (let [hiLbl (Label. "Hello World!")
        exitBtn (Button. "Exit")
        root (VBox. 12.0)]
    (.setOnAction exitBtn (reify EventHandler (handle [_ _]
                                                (Platform/exit))))
    (.setPadding root (Insets. 0 10 0 10))
    (.addAll (.getChildren root) [hiLbl exitBtn])
    (.setAlignment root Pos/CENTER)
    (.setScene stage (Scene. root 250 150)))
  (.show stage))

(defn -main [& args]
  (Application/launch sutest.core args))

当程序直接使用lein run或从IntelliJ IDEA/草书“运行”配置执行时,程序可以按预期运行。运行lein uberjar完成时没有错误,但正在尝试运行uberjar

代码语言:javascript
复制
java -jar target/sutest-0.1.0-SNAPSHOT-standalone.jar

产生

代码语言:javascript
复制
Error: JavaFX runtime components are missing, and are required to run this application

我使用Leiningen 2.9.6是因为2.9.7的this issue。运行该程序时,Leiningen会在本地依赖库中构建一个包含所需jars的类路径。

我看到了一些关于在Java的“胖”jars中包含较新的JavaFX模块的问题,并尝试将它们包含在Leiningen构建中。与Clojure和Java相关的很少。例如,请参阅fn-fx库的project.clj。它求助于一个特殊的“泄漏”配置文件来包含模块。出于某种原因,这对我不起作用。

我已经尝试将模块添加到IDEA/Cursive项目中。正确下载了项目信息中的模块,但仍然没有使用这些模块构建uberjar。

我也摆弄过IDEA/草书项目的“工件”部分。但这并不成功。

Gluon网站上有一些教程介绍了如何制作一个包含JavaFX组件的“胖”jar,但这些教程都是针对Java项目的。

Leiningen可以用来创建包含依赖项的uberjar吗?

如果不是Leiningen,那么tools.deps或boot呢?

有没有人通过修改Gluon指令成功地退回到普通的Maven构建?

EN

回答 1

Stack Overflow用户

发布于 2021-10-30 21:01:19

在@珠海的建议之后,我查看了在原始问题中创建的uberjar的内容。我用过

代码语言:javascript
复制
jar tvf jar tvf target/sutest-0.1.0-SNAPSHOT-standalone.jar

它生成了一页又一页的类列表。

靠近顶部的是以下几行:

代码语言:javascript
复制
...
   306 Sat Oct 23 15:23:46 EDT 2021 javafx-controls-17.0.1.jar
   306 Sat Oct 23 15:23:46 EDT 2021 javafx-graphics-17.0.1.jar
   302 Sat Oct 23 15:23:46 EDT 2021 javafx-base-17.0.1.jar
746012 Sat Oct 23 15:23:46 EDT 2021 javafx-base-17.0.1-mac.jar
2545243 Sat Oct 23 15:23:48 EDT 2021 javafx-controls-17.0.1-mac.jar
4852153 Sat Oct 23 15:23:48 EDT 2021 javafx-graphics-17.0.1-mac.jar
...

lein run命令构建的类路径中使用的大小相同的jars。

因此,uberjar中已经包含了所需的JavFX模块jars。

这触发了关于message thread模块的sun.launcher.LauncherHelper类对JavaFX应用程序的特殊处理的模糊记忆。(如果您感兴趣,这个类的Java17版本的源代码是here。)启动器对正在启动的主类进行特殊检查。如果它扩展了javafx.application.Application,则JavaFX模块必须存在于模块路径上,否则将显示原始问题中的错误消息,并中止启动。上面提到的消息线程和this StackOverflow answer给出了更好的解释。

最终结果是不能从javafx.application.Application类扩展JavaFX "fat“jar的主程序条目。相反,您可以使用“普通”主类,然后调用程序的JavaFX部分。

下面的项目清单是对原始问题中的项目清单的轻微编辑,并实现了描述的解决方案。

以下是修改后的project.clj。只有带有程序入口点的:main类的名称发生了更改。

代码语言:javascript
复制
(defproject sutest "0.1.0-SNAPSHOT"
  :description "Test for including JavaFX components in uberjar"
  :dependencies [[org.clojure/clojure "1.10.3"]
                 [org.openjfx/javafx-controls "17.0.1"]]
  :aot :all
  :main sutest.launcher)

下面是用于启动JavaFX部分的新类:

代码语言:javascript
复制
(ns sutest.launcher
  (:gen-class)
  (:require [sutest.core :as sc]))

(defn -main [& args]
  (sc/start-it args))

它使用新的start-it函数调用sutest.core名称空间

以下是原始JavaFX程序的修订版。start-it函数代替前面使用的-main函数启动程序。不过,请注意args参数的更改。它不再具有& rest签名。它必须是字符串的vector (可能为空)。标签和按钮的变量名称已经更改,以反映Clojure变量的命名约定。

代码语言:javascript
复制
(ns sutest.core
  (:gen-class
    :extends javafx.application.Application)
  (:import
    [javafx.application Application Platform]
    [javafx.event EventHandler]
    [javafx.geometry Insets Pos]
    [javafx.scene Scene]
    [javafx.scene.control Button Label]
    [javafx.scene.layout VBox]))

(defn -start [_ stage]
  (let [hi-lbl (Label. "Hello World!")
        exit-btn (Button. "Exit")
        root (VBox. 12.0)]
    (.setOnAction exit-btn (reify EventHandler (handle [_ _]
                                                (Platform/exit))))
    (.setPadding root (Insets. 0 10 0 10))
    (.addAll (.getChildren root) [hi-lbl exit-btn])
    (.setAlignment root Pos/CENTER)
    (.setScene stage (Scene. root 250 150)))
  (.show stage))

(defn start-it [args]
  (Application/launch sutest.core args))

就这样。现在您可以构建一个uberjar并从命令行运行它。此外,它仍然可以使用lein run命令直接从Leiningen运行,也可以在集成开发环境中运行(在使用运行配置中的入口点更改类的名称之后)。

这是一个肮脏的黑客

它基于对启动器内部结构的详细了解,而不是使用模块。在启动时,该程序仍会给出如下警告:

代码语言:javascript
复制
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @25b2b199'

希望它能工作足够长的时间,弄清楚如何在Clojure中的“胖”jars中使用Java模块。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69770989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档