For a project I'm doing I will soon have to use the Java Native interface. I tried to get started with it by reading this tutorial on it over on the IBM DeveloperWorks site.
Basically, it told me to write this class:
public class Sample1 {
public native int intMethod( int n );
public native boolean booleanMethod( boolean bool );
public native String stringMethod( String text );
public native int intArrayMethod( int[] intArray );
public static void main( String[] args ){
try{
System.loadLibrary( "Sample132" );
} catch( UnsatisfiedLinkError e ){
System.out.println( "Linking failed with message\n" + e.getMessage() );
}
Sample1 sample = new Sample1();
int square = 0, sum = 0;
boolean bool = false;
String text = "";
try{
square = sample.intMethod( 5 );
bool = sample.booleanMethod( true );
text = sample.stringMethod( "JAVA" );
sum =
sample.intArrayMethod(
new int[]{ 1, 1, 2, 3, 5, 8, 13 } );
} catch( UnsatisfiedLinkError e ){
System.out.println( "Calling native method failed with\n" + e.getMessage() );
System.exit( 1 );
}
System.out.println( "intMethod: " + square );
System.out.println( "booleanMethod: " + bool );
System.out.println( "stringMethod: " + text );
System.out.println( "intArrayMethod: " + sum );
}
}
This class just contains some simple native methods. In its main method, it tries to load the DLL containing the implementations of these. I generated the appropriate header file (Sample1.h) for the class with javah. My C++ file containing the implementation looks as follows:
#include "Sample1.h"
#include <string.h>
extern "C" {
JNIEXPORT jint JNICALL Java_Sample1_intMethod
( JNIEnv * env,
jobject obj,
jint num ){
return( num * num );
}
JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
( JNIEnv * env,
jobject obj,
jboolean boolean ){
return( ! boolean );
}
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
( JNIEnv * env,
jobject obj,
jstring string ){
const char * str = env->GetStringUTFChars( string, 0 );
char cap[ 128 ];
strcpy( cap, str );
env->ReleaseStringUTFChars( string, 0 );
return( env->NewStringUTF( strupr( cap ) ) );
}
JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
( JNIEnv * env,
jobject obj,
jintArray array ){
int i, sum = 0;
jsize len = env->GetArrayLength( array );
jint * body = env->GetIntArrayElements( array, 0 );
for( i=0; i < len; i++ ){
sum += body[ i ];
}
env->ReleaseIntArrayElements(array, body, 0);
return( sum );
}
}
The problem I have now is that as soon as the Sample1 class' main method hits the call to the native intMethod on its instance, it crashes with a UnsatisfiedLinkError runtime exception. Now, the DLL is just residing in the same directory as the class and I have verified that the main function actually loads the library successfully: it doesn't throw an UnsatisfiedLinkError exception in the System.loadLibrary() call. But for completeness sake, I was wondering whether the way I compile the DLL with MinGW's G++ has anything to do with the call failing:
g++ -I"C:\Program Files (x86)\Java\jdk1.8.0_172\include" -I"C:\Program Files (x86)\Java\jdk1.8.0_172\include\win32" -fPIC --shared -m32 -o Sample132.dll Sample1.cpp
I should also note that I'm running the class in the 32-bit JVM and it's a 32 bit DLL!
Finally, with MS VS's dumpbin tool, I got this output:
Dump of file Sample132.dll
File Type: DLL
Section contains the following exports for Sample132.dll
00000000 characteristics
5B4F79B4 time date stamp Wed Jul 18 19:32:36 2018
0.00 version
1 ordinal base
4 number of functions
4 number of names
ordinal hint RVA name
1 0 000012DE Java_Sample1_booleanMethod@12
2 1 00001368 Java_Sample1_intArrayMethod@12
3 2 000012D0 Java_Sample1_intMethod@12
4 3 000012F5 Java_Sample1_stringMethod@12
Summary
1000 .CRT
1000 .bss
1000 .data
1000 .debug_abbrev
1000 .debug_aranges
2000 .debug_info
1000 .debug_line
1000 .edata
1000 .eh_frame
1000 .idata
1000 .rdata
1000 .reloc
1000 .text
1000 .tls
So it doesn't seem like the symbols were mangled and thus the JVM wouldn't be able to find the correct symbols inside the loaded DLL.
Is there anyone who knows why my program fails with a UnsatisfieLinkError when it calls the native methods? Some help would be greatly appreciated!
Thanks in advance, Joshua
EDIT: this is the C++ file that still won't compile
#include "Sample1.h"
#include <string.h>
JNIEXPORT jint JNICALL Java_Sample1_intMethod
( JNIEnv * env,
jobject obj,
jint num ){
return( num * num );
}
JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
( JNIEnv * env,
jobject obj,
jboolean boolean ){
return( ! boolean );
}
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
( JNIEnv * env,
jobject obj,
jstring string ){
const char * str = env->GetStringUTFChars( string, 0 );
char cap[ 128 ];
strcpy( cap, str );
env->ReleaseStringUTFChars( string, 0 );
return( env->NewStringUTF( strupr( cap ) ) );
}
JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
( JNIEnv * env,
jobject obj,
jintArray array ){
int i, sum = 0;
jsize len = env->GetArrayLength( array );
jint * body = env->GetIntArrayElements( array, 0 );
for( i=0; i < len; i++ ){
sum += body[ i ];
}
env->ReleaseIntArrayElements(array, body, 0);
return( sum );
}
void main(){}