Reputation: 26
I have a C routine that is calling a Java module through the JNI invocation interface. I've been having an issue where the call to the Java method has been returning a NULL string when using the C module and the JNI, but when I use Java at the command line, the Java module returns an error and a default value.
Here is the data returned when I bypass the C code and call the Method through Java at the command line
$ java ClassName "This" "is" "my" "test" "string"
Exception on SomethingElse.Method: [Function: DifferentMethod]ExceptionClassException: ExceptionClassExceptionException: [Function: CFBDynamicMessage::getCodePage]codePageBytes is NULL, for UTF-8Returned String -- data I'm trying to get
0.0| |0.0| |0.0|| |0.0|0| |0.0| | ||0.0|0|0|0|0|0|0|0|0|0|0||
I need to get the returned string, even in the event of an error on the java side. To try to see what is going on in the C and JNI, I turned up the debugging level for the JNI:
options[1].optionString = "-Xdebug"; /* print JNI-related messages */
options[2].optionString = "-Xlog:all";
// this next line allows us to continue processing after the Java
// error. Unfortunately the code then SegFaults further on.
options[3].optionString = "-Xcheck:jni:nonfatal";
options[4].optionString = "-verbose:jni";
The JNI starts the JVM, finds the class and the method and builds the Java string I need to pass to the method, but when I try to execute the method, I get the following errors:
JVMJNCK048E JNI error in CallObjectMethod/CallObjectMethodV: Ineligible receiver JVMJNCK080E Error detected in the outermost frame of an attached thread JVMJNCK023E JNI error detected. Continuing... Segmentation fault (core dumped)
Here is the C Code (I am cutting out some error checking and whitespace for brevity):
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
cls = (*env)->FindClass(env, "GenericClassName");
mid = (*env)->GetMethodID(env, cls, "execute", "(Ljava/lang/Object;)Ljava/lang/Object;");
jstr = (*env)->NewStringUTF( env, "This|is|my|test|string|");
// This next line is the one that throws the ineligible receiver error
jstring resultStr = (*env)->CallObjectMethod(env, cls, mid, jstr);
// ExceptionOccurred(env) is false; no errors are displayed
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
const char *nativeString = (*env)->GetStringUTFChars(env, resultStr, JNI_FALSE);
// This next line calls the SegFault
fprintf(stdout, "%s\n", *nativeString);
I've used gdb to look at the core dump created by the SegFault and here are the what I think are the pertinent results:
print nativeString
$1 = 0x8dfaa80 "[Ljava.lang.Class;@34ca34ca"
print *nativeString
$2 = 91 '['
here is the definition of the java method I'm calling:
public Object execute (Object args) throws Exception { ... }
Any help or insight you can provide with this issue will be greatly appreciated. When I try to Google for the ineligible receiver error, I get a bunch of links about football, but nothing in the JNI or Java in general. I've spent the last few days scouring the Stack Overflow website, and although there were some promising questions asked, they were all related to Android and didn't provide any additional assistance in resolving my issue.
As two final notes, even if you can't help, thanks for reading this far and my environment is a 64bit RHEL server, but the C code and the JVM are both running as 32bit applications.
TL;DR - C is calling a Java Method through the JNI and I am getting an error code (JNI error in CallObjectMethod/CallObjectMethodV: Ineligible receiver) that results in Google telling me all about all the sports I can't watch because I'm working on this issue.
Upvotes: 0
Views: 2292
Reputation: 310998
You're supplying a class instead of an object. So you're trying to call Class<GenericClassName>.execute(Object arg).
You need an instance of the class.
Upvotes: 1