【问题标题】:Unsatisfied Link Error using SwingNode in OpenJFX在 OpenJFX 中使用 SwingNode 时出现不满意的链接错误
【发布时间】:2019-12-22 21:54:39
【问题描述】:

SwingNode 在使用 Spring Boot、OpenJFX 和 Maven 的应用程序中导致 Unsatisfied Link Error

我通读了有关此的帖子,尝试按照他们的建议进行操作(请参阅下面的代码),但无法解决我的问题。

有人可以帮忙吗?我哪里错了?

我正在使用我找到的 Maven 示例在 IntelliJ 中运行它。

DemoApplication

package com.javafxswingexplore.demo;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DemoApplication extends Application {

    private ConfigurableApplicationContext springContext;
    private FXMLLoader fxmlLoader;

    @Override
    public void init() throws Exception {

        System.setProperty("java.awt.headless", "false");

        springContext = SpringApplication.run(DemoApplication.class);
        fxmlLoader = new FXMLLoader();
        fxmlLoader.setControllerFactory(springContext::getBean);
    }

    @Override
    public void start(Stage stage) throws Exception {
        fxmlLoader.setLocation(getClass().getResource("/primary.fxml"));

        Parent root = fxmlLoader.load();
        Scene scene = new Scene(root);

        stage.setTitle("JavaFX and Maven");
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void stop() {
        springContext.stop();
    }

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

FXMLController

package com.javafxswingexplore.demo;

import javafx.embed.swing.SwingNode;
import javafx.fxml.FXML;
import org.springframework.stereotype.Controller;

import javax.swing.*;

@Controller
public class FXMLController {

    @FXML
    SwingNode swingNode;

    public void initialize() {

        createAndSetSwingContent(swingNode);
    }

    private void createAndSetSwingContent(final SwingNode swingNode1) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                swingNode1.setContent(new JButton("Click me!"));
            }
        });
    }
}

模块信息

module com.javafxswingexplore.demo {
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.swing;

    requires spring.boot;
    requires spring.boot.autoconfigure;
    requires spring.context;

    opens com.javafxswingexplore.demo to javafx.fxml, spring.core;
    exports com.javafxswingexplore.demo;
}

pom

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.javafxswingexplore</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>12</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-base</artifactId>
            <version>12.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-graphics</artifactId>
            <version>12.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>12.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>12.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-swing</artifactId>
            <version>12.0.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <release>12</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.3</version>
                <configuration>
                    <mainClass>com.javafxswingexplore.demo.DemoApplication</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

这是 Intellij 中的控制台输出:

"C:\Program Files\Java\jdk-12.0.1\bin\java.exe" \
--add-modules javafx.base,javafx.graphics \
--add-reads javafx.base=ALL-UNNAMED  --add-reads javafx.graphics=ALL-UNNAMED\
-XX:TieredStopAtLevel=1 -noverify \
-Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote \
-Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain \
-Dspring.application.admin.enabled=true \
"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=58874:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\bin" \
-Dfile.encoding=UTF-8 \
-p C:\Users\xxx\.m2\repository\org\openjfx\javafx-base\12.0.2\javafx-base-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\12.0.2\javafx-graphics-12.0.2-win.jar;\
C:\Users\xxx\IdeaProjects\demo\target\classes;\
C:\Users\xxx\.m2\repository\org\springframework\boot\spring-boot-starter\2.1.7.RELEASE\spring-boot-starter-2.1.7.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\boot\spring-boot\2.1.7.RELEASE\spring-boot-2.1.7.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-context\5.1.9.RELEASE\spring-context-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-aop\5.1.9.RELEASE\spring-aop-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-beans\5.1.9.RELEASE\spring-beans-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-expression\5.1.9.RELEASE\spring-expression-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.1.7.RELEASE\spring-boot-autoconfigure-2.1.7.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.1.7.RELEASE\spring-boot-starter-logging-2.1.7.RELEASE.jar;\
C:\Users\xxx\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\xxx\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;\
C:\Users\xxx\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;\
C:\Users\xxx\.m2\repository\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;\
C:\Users\xxx\.m2\repository\org\slf4j\jul-to-slf4j\1.7.26\jul-to-slf4j-1.7.26.jar;\
C:\Users\xxx\.m2\repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-core\5.1.9.RELEASE\spring-core-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\springframework\spring-jcl\5.1.9.RELEASE\spring-jcl-5.1.9.RELEASE.jar;\
C:\Users\xxx\.m2\repository\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;\
C:\Users\xxx\.m2\repository\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-base\12.0.2\javafx-base-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\12.0.2\javafx-graphics-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-controls\12.0.2\javafx-controls-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-controls\12.0.2\javafx-controls-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-fxml\12.0.2\javafx-fxml-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-fxml\12.0.2\javafx-fxml-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-swing\12.0.2\javafx-swing-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-swing\12.0.2\javafx-swing-12.0.2-win.jar\
-m com.javafxswingexplore.demo/com.javafxswingexplore.demo.DemoApplication

这是我得到的错误:

Exception in thread "JavaFX Application Thread" java.lang.UnsatisfiedLinkError: com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN.overrideNativeWindowHandle(Ljava/lang/Class;Ljdk/swing/interop/LightweightFrameWrapper;JLjava/lang/Runnable;)V
    at javafx.swing/com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN.overrideNativeWindowHandle(Native Method)
    at javafx.swing/com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN.overrideNativeWindowHandle(SwingNodeInteropN.java:128)
    at javafx.swing/javafx.embed.swing.SwingNode.notifyNativeHandle(SwingNode.java:320)
    at javafx.swing/javafx.embed.swing.SwingNode.addSceneListeners(SwingNode.java:598)
    at javafx.swing/javafx.embed.swing.SwingNode.doCreatePeer(SwingNode.java:636)
    at javafx.swing/javafx.embed.swing.SwingNode$2.doCreatePeer(SwingNode.java:137)
    at javafx.swing/com.sun.javafx.embed.swing.SwingNodeHelper.createPeerImpl(SwingNodeHelper.java:65)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.createPeer(NodeHelper.java:94)
    at javafx.graphics/javafx.scene.Node.getPeer(Node.java:2600)
    at javafx.graphics/javafx.scene.Parent.doUpdatePeer(Parent.java:177)
    at javafx.graphics/javafx.scene.Parent$1.doUpdatePeer(Parent.java:109)
    at javafx.graphics/com.sun.javafx.scene.ParentHelper.updatePeerImpl(ParentHelper.java:78)
    at javafx.graphics/com.sun.javafx.scene.layout.RegionHelper.updatePeerImpl(RegionHelper.java:72)
    at javafx.graphics/com.sun.javafx.scene.NodeHelper.updatePeer(NodeHelper.java:102)
    at javafx.graphics/javafx.scene.Node.syncPeer(Node.java:710)
    at javafx.graphics/javafx.scene.Scene$ScenePulseListener.syncAll(Scene.java:2380)
    at javafx.graphics/javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2356)
    at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2512)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:412)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:411)
    at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:438)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:562)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:542)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:535)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:341)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:835)

编辑:错误消息

在设置缓存位置和 javafx.verbose 为 true 之后 -Djavafx.cachedir=C:\\Users\\xxx\\Temp\\cache -Djavafx.verbose=true:

"C:\Program Files\Java\jdk-12.0.1\bin\java.exe" -Djavafx.cachedir=C:\\Users\\xxx\\Temp\\cache -Djavafx.verbose=true --add-modules javafx.base,javafx.graphics ... -m 
com.javafxswingexplore.demo/com.javafxswingexplore.demo.DemoApplication

JavaFX launchApplication method: launchMode=LM_MODULE
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\api-ms-win-core-console-l1-1-0.dll
...
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\msvcp140.dll
Loaded C:\Program Files\Java\jdk-12.0.1\bin\msvcp140.dll from java.library.path
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\concrt140.dll
Loaded C:\WINDOWS\system32\concrt140.dll from java.library.path
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\prism_d3d.dll
Loaded C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\bin\prism_d3d.dll from java.library.path
JavaFX: using com.sun.javafx.tk.quantum.QuantumToolkit
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\glass.dll
Loaded C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\bin\glass.dll from java.library.path
Calling main(String[]) method

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                        

2019-08-16 17:49:48.830  INFO 29056 --- [JavaFX-Launcher] o.s.boot.SpringApplication               : Starting application on DESKTOP-0DQOIUF with PID 29056 (started by xxx in C:\Users\xxx\IdeaProjects\demo)
2019-08-16 17:49:48.832  INFO 29056 --- [JavaFX-Launcher] o.s.boot.SpringApplication               : No active profile set, falling back to default profiles: default
2019-08-16 17:49:49.217  INFO 29056 --- [JavaFX-Launcher] o.s.boot.SpringApplication               : Started application in 0.692 seconds (JVM running for 1.973)
com.sun.javafx.fxml.ModuleHelper : <clinit>
getModuleMethod = public java.lang.Module java.lang.Class.getModule()
getResourceAsStreamMethod = public java.io.InputStream java.lang.Module.getResourceAsStream(java.lang.String) throws java.io.IOException
thisModule = module javafx.fxml
methodModule = module javafx.graphics
m = public javafx.collections.ObservableList javafx.scene.layout.Pane.getChildren()
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\javafx_font.dll
Loaded C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\bin\javafx_font.dll from java.library.path
WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\bin\prism_common.dll
Loaded C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\bin\prism_common.dll from java.library.path
Exception in thread "JavaFX Application Thread" java.lang.UnsatisfiedLinkError: com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN.overrideNativeWindowHandle(Ljava/lang/Class;Ljdk/swing/interop/LightweightFrameWrapper;JLjava/lang/Runnable;)V

【问题讨论】:

  • “缺失的”本机方法 overrideNativeWindowHandle 位于名为 prism_common.dll 的库中,该库与 javafx-graphics-12.0.2-win.jar 捆绑在一起。它应该可以工作,因为您已将它包含在模块路径中(使用-p),实际上您的项目在 Windows 和 Mac 上适用于我(IntelliJ -> 运行 DemoApplication)。你能发布完整的堆栈跟踪吗?
  • 感谢您的回复,何塞。我已经添加了堆栈跟踪。
  • 谢谢。您可以在 .m2 上浏览 javafx-graphics-12.0.2-win.jar 以获取 prism_common.dll 吗?如果你移除 Swing 节点,它会起作用吗?
  • 如果我只注释掉这一行:swingNode1.setContent(new JButton("Click me!")); 它可以工作。 prism_common.dll 显示在项目浏览器中的 C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\12.0.2\javafx-graphics-12.0.2-win.jar!\prism_common.dll 下。你问的是这个吗?
  • 是的,那是我的问题。您使用的是哪个 JDK 12?您可以发布从终端java -version 运行的结果吗?还要检查文件夹C:\Users\xxx\.openjfx\cache\12.0.2是否有一些dll,包括prism_common.dll

标签: java maven spring-boot javafx openjfx


【解决方案1】:

即使您有一个 Maven 项目,您也是从 IntelliJ 运行的(使用 Spring Boot 插件)。可以看到命令行:

"C:\Program Files\Java\jdk-12.0.1\bin\java.exe" \
--add-modules javafx.base,javafx.graphics \
--add-reads javafx.base=ALL-UNNAMED  --add-reads javafx.graphics=ALL-UNNAMED\
-XX:TieredStopAtLevel=1 -noverify \
-Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote \
-Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain \
-Dspring.application.admin.enabled=true \
"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=58874:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\bin" \
-Dfile.encoding=UTF-8 \
-p C:\Users\xxx\.m2\repository\org\openjfx\javafx-base\12.0.2\javafx-base-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-graphics\12.0.2\javafx-graphics-12.0.2-win.jar;\
C:\Users\xxx\IdeaProjects\demo\target\classes;\
C:\Users\xxx\.m2\repository\org\springframework\boot\spring-boot-starter\2.1.7.RELEASE\spring-boot-starter-2.1.7.RELEASE.jar;\
...
C:\Users\xxx\.m2\repository\org\openjfx\javafx-controls\12.0.2\javafx-controls-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-fxml\12.0.2\javafx-fxml-12.0.2-win.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-swing\12.0.2\javafx-swing-12.0.2.jar;\
C:\Users\xxx\.m2\repository\org\openjfx\javafx-swing\12.0.2\javafx-swing-12.0.2-win.jar\
-m com.javafxswingexplore.demo/com.javafxswingexplore.demo.DemoApplication

所有的模块都是从你的 pom 的依赖中解析出来的。并且 JavaFX 依赖项是从 Maven Central 下载的。

但是,运行项目会抛出:

线程“JavaFX 应用程序线程”中的异常 java.lang.UnsatisfiedLinkError: com.sun.javafx.embed.swing.newimpl.SwingNodeInteropN.overrideNativeWindowHandle(Ljava/lang/Class;Ljdk/swing/interop/LightweightFrameWrapper;JLjava/lang /Runnable;)V

这意味着在本机库中找不到本机方法overrideNativeWindowHandle,在本例中为prism_common.dll,它与javafx-graphics-12.0.2-win.jar 捆绑在一起。

正如 cmets 中所讨论的,为了找出失败的原因,我们首先检查了默认存储本机库的本地缓存:但是 C:\Users\xxx\.openjfx\cache\12.0.2 不存在。

尝试添加不同的缓存文件夹(使用javafx.cachedir)也无效。

但添加 -Djavafx.verbose=true 有助于在控制台日志中找出原生库的来源

从 java.library.path 加载 C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\bin\prism_common.dll

IntelliJ 正在从 java.library.path 加载 prism_common.dll,在本例中设置为路径为 C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.1\jbr\lib 的 JetBrains Runtime JBR。

可能这个JBR(无论是 8 还是 11)与 OpenJFX 源不匹配,这就是我们收到上面列出的错误的原因。

解决方案

在这种情况下,解决方案非常简单:不要依赖 JBR 库,而是直接依赖 OpenJFX 依赖项提供的库,方法是设置不同的路径。为此,只需转到 Run->Edit 配置,然后 Spring Boot -> Application,然后将此 VM 选项添加到 Environment:

-Djava.library.path=C:\temp

保存,然后再次运行。现在它应该可以按预期工作了。

【讨论】:

    猜你喜欢
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 2013-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多