Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.UnsatisfiedLinkError: URI scheme is not "file" with javafx:jlink #394

Open
srilakshmikanthanp opened this issue Jan 12, 2022 · 7 comments

Comments

@srilakshmikanthanp
Copy link

Hello i am using this library with javafx running with mvn javafx:run works fine but with mvn javafx:jlink fails to start with a launcher, here is javafx plugin xml,

<plugin>
   <groupId>org.openjfx</groupId>
   <artifactId>javafx-maven-plugin</artifactId>
   <version>0.0.6</version>
   <executions>
      <execution>
         <id>default-cli</id>
         <configuration>
            <launcher>launcher</launcher>
            <mainClass>facsimile/com.github.srilakshmikanthanp.facsimile.Launcher</mainClass>
         </configuration>
      </execution>
   </executions>
</plugin>

and Here is stake trace,

java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.UnsatisfiedLinkError: URI scheme is not "file"
        at com.github.kwhat.jnativehook@2.2-SNAPSHOT/com.github.kwhat.jnativehook.GlobalScreen.<clinit>(GlobalScreen.java:91)        
        at facsimile@1.0.0/com.github.srilakshmikanthanp.facsimile.Launcher.start(Launcher.java:34)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
        at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
        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)
        ... 1 more
Exception running application com.github.srilakshmikanthanp.facsimile.Launcher
@srilakshmikanthanp
Copy link
Author

srilakshmikanthanp commented Jan 12, 2022

See the thread on stackoverflow for more info about the error and temporary fix.

@kwhat
Copy link
Owner

kwhat commented Jan 12, 2022

You need to implement your own com.github.kwhat.jnativehook.NativeLibraryLocator for most situations. I've implemented the com.github.kwhat.jnativehook.DefaultLibraryLocator as a convince, but it doesn't work in all situations which is why NativeLibraryLocator exists. In your particular situation, the solution outlined on stackoverflow is the correct answer. I am probably just going to remove the NativeLibraryLocator functionality entirely and assume a developer using this library should understand what the java.library.path property is and how to use it.

@kwhat
Copy link
Owner

kwhat commented Jan 12, 2022

If you want me to look into this further, please provide a project (preferably Jetbrains Idea) where I can duplicate this issue.

@srilakshmikanthanp
Copy link
Author

You can find the actual project that produces the error in github. Could you give docs about how to implement com.github.kwhat.jnativehook.NativeLibraryLocator ?

@srilakshmikanthanp
Copy link
Author

Fixed with the following code

package com.github.srilakshmikanthanp.facsimile.locator;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import com.github.kwhat.jnativehook.NativeLibraryLocator;
import com.github.kwhat.jnativehook.NativeSystem;

/**
 * This class is used to locate the native libraries.
 */
public class JLibLocator implements NativeLibraryLocator {
    /**
     * This method is used to regsiter the Locator.
     */
    public static void setAaDefaultLocator() {
        System.setProperty("jnativehook.lib.locator", JLibLocator.class.getCanonicalName());
    }

    /**
     * Locates the native libraries.
     */
    @Override
    public Iterator<File> getLibraries() {
        var libs = new ArrayList<File>(1);
        var os = NativeSystem.getFamily().toString().toLowerCase();
        var arch = NativeSystem.getArchitecture().toString().toLowerCase();
        var jhome = System.getProperty("java.home");
        var libName = System.mapLibraryName("JNativeHook");
        var lib = jhome + File.separator + os + File.separator + arch + File.separator + libName;
        var libFile = new File(lib);

        libs.add(libFile);

        return libs.iterator();
    }
}

And make sure that you manually copied the dill files so image folder looks like

├───bin
│   └───server
├───conf
│   └───security
│       └───policy
│           ├───limited
│           └───unlimited
├───darwin
│   ├───arm64
│   └───x86_64
├───include
│   └───win32
├───legal
│   ├───java.base
│   ├───java.datatransfer
│   ├───java.desktop
│   ├───java.logging
│   ├───java.prefs
│   ├───java.xml
│   └───jdk.unsupported
├───lib
│   └───security
├───linux
│   ├───arm
│   ├───arm64
│   ├───x86
│   └───x86_64
└───windows
    ├───arm
    ├───x86
    └───x86_64

@srilakshmikanthanp
Copy link
Author

can we close this issue ?

@xiaodaojava
Copy link

这里要从两点去解决:
1.idea的运行。
2.使用jlink打包后的镜像怎么跑起来 , 参考:https://github.com/beryx-gist/jnativehook-modular-demo/blob/main/build.gradle

思路:
在打包之后,把对应的本地文件,复制到输出的文件夹中即可,然后实现 NativeLibraryLocator , 找到gradle任务中,对应的输出目录即可

build.gradle代码

configurations {
    resolvableImplementation { extendsFrom implementation }
}

tasks.jlink.doLast {
    configurations.runtimeClasspath.files.findAll { f ->
        f.name.contains "jnativehook"
    }.each { nativeJar ->
         // 记住这个输出目录,自定义的NativeLibraryLocator要使用
        def destDir = file("$imageDir/bin/native-libs")
        delete destDir
        mkdir destDir

        def baseLibPath = 'com/github/kwhat/jnativehook/lib'
        def zt = zipTree(nativeJar).matching {
            include "$baseLibPath/**"
        }
        def expandedPath = zt.asFileTree.tree.mirror.dir.path
        zt.files.each { f ->
            def pathInLib = (f.path - expandedPath).substring(1)
            pathInLib = pathInLib.replace('\\', '/')
            pathInLib -= "$baseLibPath/"
            def destFilePath = destDir.toPath().resolve(pathInLib)
            mkdir destFilePath.parent
            java.nio.file.Files.copy(f.toPath(), destFilePath)
        }
    }
}

自定义的 NativeLibraryLocator

import com.example.ttplayer.tools.ToolsLogger;
import com.github.kwhat.jnativehook.DefaultLibraryLocator;
import com.github.kwhat.jnativehook.NativeLibraryLocator;
import com.github.kwhat.jnativehook.NativeSystem;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

public class JLibLocator implements NativeLibraryLocator {


    DefaultLibraryLocator defaultLocator = new DefaultLibraryLocator();

    /**
     * This method is used to regsiter the Locator.
     */
    public static void setAaDefaultLocator() {
        System.setProperty("jnativehook.lib.locator", JLibLocator.class.getCanonicalName());
    }

    /**
     * Locates the native libraries.
     */
    @Override
    public Iterator<File> getLibraries() {
        var libs = new ArrayList<File>(1);
        var os = NativeSystem.getFamily().toString().toLowerCase();
        var arch = NativeSystem.getArchitecture().toString().toLowerCase();
        var jhome = System.getProperty("java.home");
        var libName = System.mapLibraryName("JNativeHook");
        // 和 build.gradle中 jink输出的目录是一致的
        var lib = jhome + File.separator +"bin"+File.separator+"native-libs"+ File.separator + os + File.separator + arch + File.separator + libName;
        var libFile = new File(lib);
        ToolsLogger.info("lib path: " + libFile.getAbsolutePath());
        if(!libFile.exists()){
            // 这一行很关键,解决idea运行的问题,如果是idea运行,使用默认的加载器执行
            return defaultLocator.getLibraries();
        }
        libs.add(libFile);

        return libs.iterator();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants