where's the bug in my little program?
I'm a fresh jni coder
I try to use native code to print the contents of integer array data in an converse object
after successfully compiling,I run it
Oops!
JVM crash buginfos fill in all my screen!!!
Help me find the bug,thank you
Test.java
publicclass Test{
publicstaticvoid main(String args[]){
Converse conv=new Converse();
conv.print();
}
}
Converse.java
publicclass Converse{
privateint[] data;
public Converse()
{
data =newint[10];
for (int i = 0; i < 10; i++)
{
data[i] = i;
}
}
publicnativevoid print();
static
{
System.loadLibrary("Converse");
}
}
#include"Converse.h"
#include <stdio.h>
JNIEXPORTvoid JNICALL Java_Converse_print(JNIEnv *env, jobject object)
{
jclass system_class;
jclass print_class;
jclass conv_class;
jclass string_class;
jfieldID out_ID;
jfieldID data_ID;
jmethodID println_ID;
jmethodID valueOf_ID;
jobject out_obj;
jarray data_array;
int length;
int *data;
int i;
system_class=(*env)->FindClass(env,"java/lang/System");
out_ID=(*env)->GetFieldID(env,system_class,"out","java/io/PrintStream");
out_obj=(*env)->GetObjectField(env,system_class,out_ID);
print_class=(*env)->GetObjectClass(env,out_obj);
println_ID=(*env)->GetStaticMethodID(env,print_class,"println","(Ljava/lang/String;)V");
conv_class=(*env)->GetObjectClass(env,object);
data_ID=(*env)->GetFieldID(env,conv_class,"data","[I");
data_array=(*env)->GetObjectField(env,object,data_ID);
length=(*env)->GetArrayLength(env,data_array);
data=(*env)->GetIntArrayElements(env,data_array,NULL);
string_class=(*env)->FindClass(env,"java/lang/String");
valueOf_ID=(*env)->GetStaticMethodID(env,string_class,"valueOf","(I)Ljava/lang/String;");
for(i=0;i<length;i++)
{
jstring datai=(*env)->CallStaticObjectMethod(env,string_class,valueOf_ID,data[i]);
(*env)->CallVoidMethod(env,out_obj,println_ID,datai);
}
}
I think I forgot some comments
In the following jni codes,
I use
System.out.println(data);
to print the contents
so I need "java.lang.System" class
and then the "out" static field,
then "java.io.PrintStream"class because it's the type of "out" field
then we get the println(String) method needed to print
and then we use String.valueOf(int) static method to tranlate the data of int type to a short string
so we must get extra classid and methodid,
firstthe "java.lang.String" class
second the "valueOf(int)" method
then we translate it
finally we use the out.println() to print the result to the console...
JNIEXPORT void JNICALL Java_Converse_print(JNIEnv *env, jobject object)
{
jclass system_class;
jclass print_class;
jclass conv_class;
jclass string_class;
jfieldID out_ID;
jfieldID data_ID;
jmethodID println_ID;
jmethodID valueOf_ID;
jobject out_obj;
jarray data_array;
int length;
int *data;
int i;
system_class=(*env)->FindClass(env,"java/lang/System");
out_ID=(*env)->GetFieldID(env,system_class,"out","java/io/PrintStream");
out_obj=(*env)->GetObjectField(env,system_class,out_ID);
print_class=(*env)->GetObjectClass(env,out_obj);
println_ID=(*env)->GetStaticMethodID(env,print_class,"println","(Ljava/lang/String;)V");
conv_class=(*env)->GetObjectClass(env,object);
data_ID=(*env)->GetFieldID(env,conv_class,"data","[I");
data_array=(*env)->GetObjectField(env,object,data_ID);
length=(*env)->GetArrayLength(env,data_array);
data=(*env)->GetIntArrayElements(env,data_array,NULL);
string_class=(*env)->FindClass(env,"java/lang/String");
valueOf_ID=(*env)->GetStaticMethodID(env,string_class,"valueOf","(I)Ljava/lang/String;");
for(i=0;i<length;i++)
{
jstring datai=(*env)->CallStaticObjectMethod(env,string_class,valueOf_ID,data);
(*env)->CallVoidMethod(env,out_obj,println_ID,datai);
}
}
There are too many errors!
☆the instance field "out" of PrintStream is static and the signature of it is "Ljava/io/PrintStream;"
☆if you want to get the value of an instance field, you should pass a object parameter, not a class parameter, and to get value of a static instance field, you should use GetStaticObjectField with a class parameter.
☆the method "println" is not a static method of PrintStream, if you are not sure about the signature of field or method, you can use javap command to see it, like javap -s java.lang.System
☆the most import thing, you should check every return value and catch possible exception use ExceptionCheck()
☆you should delete local reference
☆recommend to read the JNI specification of sun.
the corrent codes look like:
#include "Converse.h"
#include <stdio.h>
#include <jni.h>
JNIEXPORT void JNICALL Java_Converse_print(JNIEnv *env, jobject object)
{
jclass system_class;
jclass print_class;
jclass conv_class;
jclass string_class;
jfieldID out_ID;
jfieldID data_ID;
jmethodID println_ID;
jmethodID valueOf_ID;
jobject out_obj;
jarray data_array;
int length;
int *data;
int i;
system_class = (*env)->FindClass(env, "java/lang/System");
if(system_class)
{
printf("1 OK\n");
out_ID = (*env)->GetStaticFieldID(env,system_class, "out", "Ljava/io/PrintStream;");
if(out_ID)
{
printf("2 OK\n");
out_obj = (*env)->GetStaticObjectField(env, system_class, out_ID);
print_class = (*env)->GetObjectClass(env, out_obj);
if(print_class)
{
printf("3 OK\n");
println_ID = (*env)->GetMethodID(env, print_class, "println", "(Ljava/lang/String;)V");
}
}
}
conv_class = (*env)->GetObjectClass(env, object);
if(conv_class)
{
printf("4 OK\n");
data_ID = (*env)->GetFieldID(env, conv_class, "data", "[I");
if(data_ID)
{
printf("5 OK\n");
data_array = (*env)->GetObjectField(env, object, data_ID);
if(data_array)
{
printf("6 OK\n");
length = (*env)->GetArrayLength(env, data_array);
data = (*env)->GetIntArrayElements(env, data_array, JNI_FALSE);
}
}
}