Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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());
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions java-native/src/main/cpp/unsatisfiedlink/generateNativeLib.sh
Original file line number Diff line number Diff line change
@@ -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*
Original file line number Diff line number Diff line change
@@ -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();
}
3 changes: 3 additions & 0 deletions java-native/src/main/resources/unsatisfiedlink/jni.policy
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
grant {
permission java.lang.RuntimePermission "loadLibrary.test";
};
Original file line number Diff line number Diff line change
@@ -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 {
Comment thread
JavierPeris marked this conversation as resolved.

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"));
}
}