BAEL-4165 - Custom DLL Load - Fixing the "java.lang.UnsatisfiedLinkError" Error (#14393)
* first draft * review 1 * review 1 - test setup
This commit is contained in:
parent
b9180b0eb7
commit
a0649ba357
|
@ -0,0 +1,13 @@
|
|||
#include "com_baeldung_unsatisfiedlink_JniUnsatisfiedLink.h"
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
* Class: com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
* Method: test
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink_test (JNIEnv* env, jobject thisObject) {
|
||||
std::string test = "Test OK";
|
||||
std::cout << test << std::endl;
|
||||
return env->NewStringUTF(test.c_str());
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_baeldung_unsatisfiedlink_JniUnsatisfiedLink */
|
||||
|
||||
#ifndef _Included_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
#define _Included_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
* Method: test
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_baeldung_unsatisfiedlink_JniUnsatisfiedLink_test
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
# Create the header with javac -h . ClassName.java
|
||||
# Remember to set your JAVA_HOME env var
|
||||
# Don't forget to set java.library.path to point to the folder where you have the lib you're loading.
|
||||
MYSELF="$(readlink -f "$0")"
|
||||
MYDIR="${MYSELF%/*}"
|
||||
|
||||
cd "$MYDIR"
|
||||
class_name=com_baeldung_unsatisfiedlink_JniUnsatisfiedLink
|
||||
lib_name=test
|
||||
|
||||
g++ -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${class_name}.cpp -o ${class_name}.o
|
||||
g++ -shared -fPIC -o lib${lib_name}.so ${class_name}.o -lc
|
||||
|
||||
# 32-bit version
|
||||
g++ -m32 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${class_name}.cpp -o ${class_name}32.o
|
||||
g++ -m32 -shared -fPIC -o lib${lib_name}32.so ${class_name}32.o -lc
|
||||
|
||||
# dummy version
|
||||
touch ${class_name}-dummy.o
|
||||
|
||||
ls lib*
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.unsatisfiedlink;
|
||||
|
||||
public class JniUnsatisfiedLink {
|
||||
|
||||
public static final String LIB_NAME = "test";
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
new JniUnsatisfiedLink().test();
|
||||
}
|
||||
|
||||
public native String test();
|
||||
|
||||
public native String nonexistentDllMethod();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
grant {
|
||||
permission java.lang.RuntimePermission "loadLibrary.test";
|
||||
};
|
|
@ -0,0 +1,105 @@
|
|||
package com.baeldung.unsatisfiedlink;
|
||||
|
||||
import static com.baeldung.unsatisfiedlink.JniUnsatisfiedLink.LIB_NAME;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class JniUnsatisfiedLinkManualTest {
|
||||
|
||||
static String osLibPrefix = "";
|
||||
static String osLibSuffix = "";
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
String osName = System.getProperty("os.name")
|
||||
.toLowerCase();
|
||||
|
||||
if (osName.contains("win")) {
|
||||
osLibSuffix = ".dll";
|
||||
} else if (osName.contains("nix") || osName.contains("nux") || osName.contains("mac")) {
|
||||
osLibPrefix = "lib";
|
||||
osLibSuffix = ".so";
|
||||
if (osName.contains("mac")) {
|
||||
osLibPrefix = "lib";
|
||||
osLibSuffix = ".dylib";
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported operating system: " + osName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCorrectLibName_thenLibLoaded() {
|
||||
assertDoesNotThrow(() -> {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
new JniUnsatisfiedLink().test();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncorrectLibName_thenLibNotFound() {
|
||||
String libName = osLibPrefix + LIB_NAME + osLibSuffix;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libName));
|
||||
|
||||
assertEquals(String.format("no %s in java.library.path", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLoadLibraryContainsPathSeparator_thenErrorThrown() {
|
||||
String libName = "/" + LIB_NAME;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libName));
|
||||
|
||||
assertEquals(String.format("Directory separator should not appear in library name: %s", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLoadWithoutAbsolutePath_thenErrorThrown() {
|
||||
String libName = LIB_NAME;
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.load(libName));
|
||||
|
||||
assertEquals(String.format("Expecting an absolute path of the library: %s", libName), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUnlinkedMethod_thenErrorThrown() {
|
||||
System.loadLibrary(LIB_NAME);
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> new JniUnsatisfiedLink().nonexistentDllMethod());
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("JniUnsatisfiedLink.nonexistentDllMethod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenIncompatibleArchitecture_thenErrorThrown() {
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(LIB_NAME + "32"));
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("wrong ELF class: ELFCLASS32"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCorruptedFile_thenErrorThrown() {
|
||||
String libPath = System.getProperty("java.library.path");
|
||||
assertNotNull(libPath);
|
||||
|
||||
String dummyLib = LIB_NAME + "-dummy";
|
||||
assertTrue(new File(libPath, osLibPrefix + dummyLib + osLibSuffix).isFile());
|
||||
|
||||
Error error = assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(dummyLib));
|
||||
|
||||
assertTrue(error.getMessage()
|
||||
.contains("file too short"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue