JNI can't look up inner class

A

Arne

Hi-
I have a question regarding JNI. I am trying to call a method in an
inner class from C++. Have been hunting around a bit, but am very
confused. With the following Java code and javap -s I don't get the
inner class's methods (regardless of whether I make the inner class
static or not):

public class Caller {
int x = 0;
public static class Inner {
int y = 0;
public int get() {
return y;
}
}
}

javap -s Caller gives:
public class Caller extends java.lang.Object{
int x;
Signature: I
public Caller();
Signature: ()V
}

(ditto when I call javap -s Caller$Inner btw).

Now when in my code snippet I try to call the get() method like this
(deducing the method signature):

jclass jcls = env->FindClass("Caller$Inner");
jmethodID jm = env->GetMethodID(jcls, "<init>", "()V");
jobject jobj = env->NewObject(jcls, jm);
jm = env->GetStaticMethodID(jcls, "get", "V(I)");
jint jnt = env->CallIntMethod(jobj, jm);

The call to GetStaticMethodID fails with

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# SIGSEGV (0xb) at pc=0xb79721cb, pid=16424, tid=3074430656
#
# Java VM: Java HotSpot(TM) Server VM (1.5.0_16-b02 mixed mode)
# Problematic frame:
# V [libjvm.so+0x2bf1cb]
#
# An error report file with more information is saved as
hs_err_pid16424.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#

Any ideas? This seems very broken to me, as javap isn't even finding
the inner class's get method.

Many thanks
 
A

Arved Sandstrom

Arne said:
Hi-
I have a question regarding JNI. I am trying to call a method in an
inner class from C++. Have been hunting around a bit, but am very
confused. With the following Java code and javap -s I don't get the
inner class's methods (regardless of whether I make the inner class
static or not):

public class Caller {
int x = 0;
public static class Inner {
int y = 0;
public int get() {
return y;
}
}
}
[ SNIP ]

I can't speak to the behaviour of javap in this situation, but your class
Inner is not an inner class when it's declared as static.

AHS
 
A

Arne

public class Caller {
int x = 0;
public static class Inner {
int y = 0;
public int get() {
return y;
}
}
}

[ SNIP ]

I can't speak to the behaviour of javap in this situation, but your class
Inner is not an inner class when it's declared as static.

AHS

Thanks. Don't know the terminology sorry. The problem remains,
regardless of whether the class is declared static or not (for C++,
the only implication appears to be that the static class doesn't need
to know the instance of the outer class). It also doesn't make a
difference about whether I use GetMethodID instead of
GetStaticMethodID - the method simply is not found!
 
J

jolz

(ditto when I call javap -s Caller$Inner btw).

Show us result of that command. It should show get()'s signature.
jm = env->GetStaticMethodID(jcls, "get", "V(I)");

Method get() isn't static.
Signature is wrong. javap will show signature similar to constructor's
but with changed return type from void to int.
# SIGSEGV (0xb) at pc=0xb79721cb, pid=16424, tid=3074430656
#
# Java VM: Java HotSpot(TM) Server VM (1.5.0_16-b02 mixed mode)
# Problematic frame:
# V [libjvm.so+0x2bf1cb]

This shouild never happen. If exceptions aren't thrown, allways check
for possible error after a function call. The error is caused by NULL jm
- this should be checked before passing jm to CallIntMethod().
 
A

Arne

Show us result of that command. It should show get()'s signature.

It doesn't:

$ more ../src-java/Caller.java

public class Caller {
int x = 0;
public Caller() {

}
public static class Inner {
int y = 0;
public int get() {
return y;
}
}

}

$ javap -s Caller
Compiled from "Caller.java"
public class Caller extends java.lang.Object{
int x;
Signature: I
public Caller();
Signature: ()V
}
Method get() isn't static.
Signature is wrong. javap will show signature similar to constructor's
but with changed return type from void to int.

I understand. As mentioned above, GetMethodID also doesn't find the
method. The signature should probably be "()I", but that also throws
the same exception.

env->ExceptionDescribe() returns:
Exception in thread "main" java.lang.NoSuchMethodError: get

which makes some sense.


But can anyone explain why javap doesn't show the get method and why
JNI can't find it either?
 
J

jolz

(ditto when I call javap -s Caller$Inner btw).
$ javap -s Caller

This one we have already seen. Show us result of a command I quoted.
The signature should probably be "()I",

Yes. And it's exactly what javap shows.
but that also throws
the same exception.

Show us the code with corrected both mistakes (preferably in a simplest
possible compilable program). It should work.
 
A

Arne

This one we have already seen. Show us result of a command I quoted.


Yes. And it's exactly what javap shows.

I simplified a bit. Oddly enough, it shows:

$ more ../src-java/Caller.java

public class Caller {
public static class Inner {
public int get() {
return 42;
}
}
}
$ javap -s Caller$Inner
Compiled from "Caller.java"
public class Caller extends java.lang.Object{
public Caller();
Signature: ()V
}
Show us the code with corrected both mistakes (preferably in a simplest
possible compilable program). It should work.

OK. There must have been a typo that I can't reproduce anymore -
because it works now. WTF? Thanks for being persistent with me.

Just for reference here's the C/C++ code that successfully calls the
method in the inner class, all error checks removed for brevity/
clarity:

#include <jni.h>

int main(int argc, char **argv) {
JavaVMInitArgs vm_args;
JavaVMOption options[5];
JNIEnv *env;
JavaVM *jvm;

options[0].optionString = (char *) "-Xms4M";
options[1].optionString = (char *) "-Xmx64M";
options[2].optionString = (char *) "-Xss512K";
options[3].optionString = (char *) "-Xoss400K";
options[4].optionString = (char *) "-Djava.class.path=.";

vm_args.version = JNI_VERSION_1_4;
vm_args.options = options;
vm_args.nOptions = 5;
vm_args.ignoreUnrecognized = JNI_FALSE;

int res = JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);
jclass jcCaller = env->FindClass("Caller");
jmethodID jm = env->GetMethodID(jcCaller, "<init>", "()V");
jobject joCaller = env->NewObject(jcCaller, jm);
jclass jcInner = env->FindClass("Caller$Inner");
jm = env->GetMethodID(jcInner, "<init>", "()V");
jobject joInner = env->NewObject(jcInner, jm);
jm = env->GetMethodID(jcInner, "get", "()I");
jint jres = env->CallIntMethod(joInner, jm);
printf("Inner get call:%d\n", jres);

}

Thanks a lot for spending your cycles helping out.
 
J

Joshua Cranmer

Arne said:
$ javap -s Caller$Inner
Compiled from "Caller.java"
public class Caller extends java.lang.Object{
public Caller();
Signature: ()V
}

In any bash shell, you'd want to do Caller\$Inner, because, otherwise,
it's trying to interpret $Inner as a variable (and is therefore
returning the empty string). Notice how your javap isn't looking at
Caller$Inner but Caller.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top