java-cef icon indicating copy to clipboard operation
java-cef copied to clipboard

Native Library jawt.dll already loaded in another classloader

Open magreenblatt opened this issue 6 years ago • 8 comments

Original report by Leah (Bitbucket: Leah, GitHub: Leah).


I'm trying to write a plugin for IDEA which integrates chromium as a webview, not sure if this error is on me, but any help would be appreciated

java.lang.UnsatisfiedLinkError: Native Library C:\Users\harmony\.gradle\caches\modules-2\files-2.1\com.jetbrains\jbre\jbrex8u152b1343.15_windows_x64\jre\bin\jawt.dll already loaded in another classloader
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1907)
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1845)
	at java.lang.Runtime.loadLibrary0(Runtime.java:870)
	at java.lang.System.loadLibrary(System.java:1122)
	at org.cef.CefApp.<init>(CefApp.java:138)
	at org.cef.CefApp.getInstance(CefApp.java:213)
	at org.cef.CefApp.getInstance(CefApp.java:200)
	at org.panda_lang.pandomium.wrapper.PandomiumCEF.initialize(PandomiumCEF.java:16)
	at org.panda_lang.pandomium.Pandomium.lambda$initialize$0(Pandomium.java:34)
	at org.panda_lang.pandomium.loader.PandomiumLoader.callListeners(PandomiumLoader.java:56)
	at org.panda_lang.pandomium.loader.PandomiumLoaderWorker.load(PandomiumLoaderWorker.java:46)
	at org.panda_lang.pandomium.loader.PandomiumLoaderWorker.run(PandomiumLoaderWorker.java:21)
	at java.lang.Thread.run(Thread.java:745)

It's loaded from here https://bitbucket.org/chromiumembedded/java-cef/src/d64cd6c266d5a9fc485bdfb6d5b672201dc5dfc7/java/org/cef/CefApp.java?at=master#lines-138

magreenblatt avatar Dec 28 '18 15:12 magreenblatt

Original comment by Simon Haisz (Bitbucket: sihaisz, GitHub: sihaisz).


This issue happens because another classloader already loaded jawt.dll for some purpose. We ran into this issue because the Java Access Bridge (used for accessibility) loaded the dll first. Likely IDEA itself that is doing it. The annoying thing is that there is no way to check if a native dll is already loaded apart from trying and catching this exception. This is made more annoying because UnsatisfiedLinkError is used for a variety of errors, some of which should cause your program to crash, so you have to resort to checking the exception message.

This is the work around that we ended up using:

#!java
try {
	System.loadLibrary("jawt"); //$NON-NLS-1$
} catch(UnsatisfiedLinkError e) {
	String message = e.getMessage();
	if(!message.startsWith("Native Library") || !message.endsWith("already loaded in another classloader")) { //$NON-NLS-1$ //$NON-NLS-2$
		throw e;
	}
	System.out.println("Failed loading jawt.dll. It is already loaded by another classloader."); //$NON-NLS-1$
}

Something like this should probably be promoted to master. We didn't create a PR because we have other changes around initialization that only apply to our application. If you are concerned about trusting your program flow to an exception message that could be changed in any release (and you should be...) please note that our workaround has been in production for 3 years and we haven't had to touch it since.

magreenblatt avatar Dec 29 '18 01:12 magreenblatt

Original comment by Leah (Bitbucket: Leah, GitHub: Leah).


It's kinda confusing to me that java wouldn't handle that by itself

magreenblatt avatar Jan 01 '19 17:01 magreenblatt

Original comment by Nol Moonen (Bitbucket: nolmoonen, GitHub: nolmoonen).


Hello, I am having the exact same issue with IDEA. However, I stumbled upon a way to check if the library is loaded, without relying on this exception message flow. It basically comes down to:

try {
    java.lang.reflect.Field libraryNames;
    libraryNames = ClassLoader.class.getDeclaredField("loadedLibraryNames");
    libraryNames.setAccessible(true);
    Vector<String> libraries = (Vector<String>) libraryNames.get(ClassLoader.getSystemClassLoader());
    if (!libraries.contains("jawt")) {
        System.loadLibrary("jawt");
    }
} catch (NoSuchFieldException | IllegalAccessException e) {
    e.printStackTrace();
}

I am quite unsure whether this is something you'd want on the master branch, since it seems like a hack. However, it is still a serious issue to me. Should I make a pull request for this?

magreenblatt avatar Apr 29 '19 18:04 magreenblatt

Original comment by Max Senft (Bitbucket: Max Senft).


Hmhm, as there’s a pull request (https://bitbucket.org/chromiumembedded/java-cef/pull-requests/39/fix-loading-already-loaded-native-library/diff) now, I wonder if this is actually the correct solution. It looks more like a workaround to me, as the Java documentation states that subsequent calls of loadLibrary() will be ignored (see https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#loadLibrary-java.lang.String-).

I tested this problem by myself, by loading the "jawt" library immediately in Main() of my program and did not get an exception later, when loading the JCEF…

magreenblatt avatar Aug 26 '19 12:08 magreenblatt

I believe applications should now be able to work around this issue with the SystemBootstrap class added in fbfa9202 (bb).

magreenblatt avatar Jun 30 '20 15:06 magreenblatt

If SystemBootstrap is insufficient we can re-open.

magreenblatt avatar Jun 30 '20 15:06 magreenblatt

  • changed state from "new" to "closed"

magreenblatt avatar Jun 30 '20 15:06 magreenblatt

Related PR: https://bitbucket.org/chromiumembedded/java-cef/pull-requests/71

magreenblatt avatar Jan 09 '24 18:01 magreenblatt