'Java problem loading native lib inside jar

(I slightly re-edited my post as I found out that I need just one native lib, not all 4 as previously thought)

I am on Windows 7 x64, and I try to pack my native lib into the JAR using this code (BTW I also tried basically all the other codes from that page - result the same for all of them in my case!!!).

My modded code looks like this:

static {
    try {
        //EXTRACT NATIVE LIB(S) FROM JAR
        String libName = "lwjgl64.dll";
        URL url = Class.class.getResource("/natives/" + libName);
        File tmpDir = new File(App.FILE_APPPATH.getAbsolutePath() + "/libs");
        if (tmpDir.exists()) {
            FileUtils.deleteDirectory(tmpDir);
        }
        tmpDir.mkdir();
        File nativeLibTmpFile = new File(tmpDir, libName);
        try (InputStream in = url.openStream()) {
            Files.copy(in, nativeLibTmpFile.toPath());
        }

        //ADD PATH TO EXTRACTED LIBS FOLDER TO JAVA
        System.setProperty("java.library.path", tmpDir.getAbsolutePath());
        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);
        //System.err.println("'" + System.getProperty("java.library.path") + "'");

        //LOAD LIB DLL FILE(S)
        //System.err.println("'" + nativeLibTmpFile.getAbsolutePath() + "'");
        System.load(nativeLibTmpFile.getAbsolutePath());
    } catch (IOException | SecurityException | IllegalArgumentException | NoSuchFieldException | IllegalAccessException  ex) {
        Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
    }
}

I added this code to my main class, and run my Java app from the NetBeansIDE - running my java App like this all seem to be OK and working correctly, no error whatsoever

But when I compile my project/App to JAR, run it (that is now already outside the NetBeansIDE started by BAT file) then as soon as there is a method or function that requires that native lib I got this error:

Exception in thread "Thread-12" java.lang.NoClassDefFoundError: org/lwjgl/system/FunctionProvider
        at org.lwjgl.opengl.GL11.<clinit>(GL11.java:38)
        at org.lwjgl.opengl.GLContext.getSupportedExtensions(GLContext.java:228)
        at org.lwjgl.opengl.ContextCapabilities.initAllStubs(ContextCapabilities.java:5802)
        at org.lwjgl.opengl.ContextCapabilities.<init>(ContextCapabilities.java:6240)
        at org.lwjgl.opengl.GLContext.useContext(GLContext.java:374)
        at org.lwjgl.opengl.ContextGL.makeCurrent(ContextGL.java:195)
        at org.lwjgl.opengl.DrawableGL.makeCurrent(DrawableGL.java:110)
        at org.lwjgl.opengl.Display.makeCurrent(Display.java:706)
        at org.lwjgl.opengl.Display.makeCurrentAndSetSwapInterval(Display.java:1025)
        at org.lwjgl.opengl.Display.create(Display.java:852)
        at org.lwjgl.opengl.Display.create(Display.java:797)
        ...

From this I would say it still does not know where the native lib is - right? I double checked that the native lib is successfully extracted from the JAR to specified created directory when my app is started via BAT file...and yes, it is.

My BAT file code looks like this:

@ECHO OFF
java -XX:+UseG1GC -Xmx1G -server -jar data.jar %*
@if %errorlevel% neq 0 pause

How come it works perfectly as expected when run from NetBeansIDE but it is unable to locate/load already successfully extracted and correctly added native lib file (it is already added directly from inside the app via the code above)?

Can anyone tell me what is wrong with my code or how to make it correctly?

Maybe some values in the BAT file that should not be there when one is using native libs (remember that I do not need to add -Djava.library.path to my BAT file as I have packed my native lib inside the JAR)? You see: I never used native libs before, this is my first time ever.

BTW I also tried to add that -Djava.library.path to the BAT with the absolute path to the folder with the native libs (I have no spaces in the path), yet the result is absolutely the same...strange, like something in the OS preventing the access tho i have to immediately say probably not, cos it has no problem accessing it from the NetBeansIDE - this is really specific just to the compiled final JAR file + BAT (or at least that is how I see it at the moment).

UPDATE 2022-05-06

After several other tests I am very close to believe this issue might actually be caused by the Windows 7 x64 OS dealing with file permissions, according to DLL file permissions causes not working post. But if that is the case, how come others have no such problems when deploying their java apps with native libs...or is it really some sort of Windows 7 x64 specific issue? Also I do not know how to make it work cos I already added full permission for the whole directory of my java projects yet it still behaves the same.



Solution 1:[1]

First off some good advices:

  • remove all unnecessary jar files from your project (they might cause problems similar to yours)
  • do not mix different versions of LWJGL jar files (might cause problems similar to yours)
  • do not mix different versions of LWJGL native .dll files (might cause problems similar to yours)
  • use only really needed native .dll files (sometime unnecessary ones may cause errors like yours)

Now here is your code updated by me for automatic detection of all native files in internal natives folder without need of manually defining them + rest is basically yours - tested myself, all works as it should.

//INITIALIZATION OF NATIVE LIBS PACKED INSIDE THE COMPILLED JAR
static {
    try {
        String internalNativesFolder = "natives";

        //EXTRACT NATIVE LIB(S) FROM JAR
        File tmpDir = new File(App.FILE_APPPATH.getAbsolutePath() + App.LOMKA_R + internalNativesFolder);
        if (tmpDir.exists()) {
            FileUtils.deleteDirectory(tmpDir);
        }
        tmpDir.mkdir();

        //GETS ALL FILES IN INTERNAL NATIVES FOLDER
        URI uri = App.class.getResource(App.LOMKA_R + internalNativesFolder).toURI();
        Path myPath;
        if (uri.getScheme().equals("jar")) {
            FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
            myPath = fileSystem.getPath(App.LOMKA_R + internalNativesFolder);
        } else {
            myPath = Paths.get(uri);
        }
        Stream<Path> walk = Files.walk(myPath, 1);
        List<String> libNames = new ArrayList<>();
        for (Iterator<Path> it = walk.iterator(); it.hasNext();) {
            String fN = it.next().getFileName().toString();
            if (!fN.equals(internalNativesFolder)) {
                libNames.add(fN);
            }
        }

        //COPIES THOSE FILES TO TEMPORARY LOCAL DIRECTORY
        for (String libName : libNames) {
            URL url = Class.class.getResource(App.LOMKA_R + internalNativesFolder + App.LOMKA_R + libName);
            File nativeLibTmpFile = new File(tmpDir, libName);
            try (InputStream in = url.openStream()) {
                Files.copy(in, nativeLibTmpFile.toPath());
            }
        }

        //ADD PATH TO EXTRACTED LIBS FOLDER TO JAVA
        System.setProperty("java.library.path", tmpDir.getAbsolutePath());
        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);

        //LOAD LIB DLL FILE(S)
        libNames.forEach(libName -> {
            System.load(new File(tmpDir, libName).getAbsolutePath());
        });

    } catch (IOException | SecurityException | IllegalArgumentException | NoSuchFieldException | IllegalAccessException | URISyntaxException ex) {
        Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1