JNI: Calling Java Method with String as Parameter from C

Discussion in 'Java' started by Daniel.Boegelein@gmx.de, Apr 16, 2007.

  1. Guest

    Hi,

    In my C Method i try to call a Method, which expects a String as
    Parameter. Therefore the String will be created in the c function and
    then passed to the java method. Everything works fine, expect of the
    fact, that i get in the Java Method a String object with length 0 :(

    The strange thing is, that in the c code the jstring object seems to
    be correct (getUtfSize() returns the right length). But on Java Side
    the length is 0. So what am i doing wrong???? I thought about it the
    whole day without finding any solution!

    Thanks for your help in advance!!!

    Source Code:

    Java:

    private synchronized boolean internalNotifyCallback(String obj)
    {
    if(obj != null) {
    System.out.println(obj.length());
    System.out.println("object is not null : " + obj);
    }

    if(closeNotify){
    System.out.println("CloseNotify is " + closeNotify);
    }
    return !closeNotify;
    }

    C:
    void listenXYZ(RXPARAMS par)
    {
    ....

    jsize count;
    jmethodID jmid;
    jclass icls;
    jboolean continueListening = 1;

    char string[50];

    RXPARAMS prxParams = par;


    JNIEnv *env = par.env;

    .....

    icls = (*env)->GetObjectClass(env, prxParams.jobj);
    //get CallBack Address
    jmid = (*env)->GetMethodID(env, icls,
    "internalNotifyCallback","(Ljava/lang/String;)Z");

    writeLog("after getMID\n");
    if (jmid == 0){
    writeLog("jmid == NULL\n");
    }

    const char *pWelt = "Hello World";

    jstring jStr = NULL;
    jStr = (*env)->NewStringUTF(env, pWelt);


    if (jStr != NULL){
    jsize size = (*env)->GetStringUTFLength(env,jStr);
    writeLog("Is Not Null. Size: %d \n", size);
    }
    else
    writeLog("Is Null\n");

    continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    jmid, eventObj, jStr);
    }


    P.S. I know that my english isn't very good - but i try to improve it,
    so please be lenient toward me ;)
     
    , Apr 16, 2007
    #1
    1. Advertising

  2. On 16 Apr 2007 07:51:29 -0700, wrote:
    > Everything works fine, expect of the fact, that i get in the Java
    > Method a String object with length 0 :(


    [...]

    > Java:
    > private synchronized boolean internalNotifyCallback(String obj)


    [...]

    > C:
    > continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    > jmid, eventObj, jStr);


    Your method is declared to take one object - a String. You're passing
    it two - an eventObj and a String.

    It doesn't appear that eventObj was the String that you intended to
    use here, but its declaration is missing from your post.

    If eventObj really is a String, then its length is 0.

    If eventObj isn't a String, the length reported by the receiving
    method cannot be trusted here, and the JVM will be left in an unstable
    state (and will eventually crash if you make a habit of this).

    /gordon

    --
     
    Gordon Beaton, Apr 16, 2007
    #2
    1. Advertising

  3. Guest

    On 16 Apr., 18:21, Gordon Beaton <> wrote:
    > On 16 Apr 2007 07:51:29 -0700, wrote:
    >
    > > Everything works fine, expect of the fact, that i get in the Java
    > > Method a String object with length 0 :(

    >
    > [...]
    >
    > > Java:
    > > private synchronized boolean internalNotifyCallback(String obj)

    >
    > [...]
    >
    > > C:
    > > continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    > > jmid, eventObj, jStr);

    >
    > Your method is declared to take one object - a String. You're passing
    > it two - an eventObj and a String.
    >
    > It doesn't appear that eventObj was the String that you intended to
    > use here, but its declaration is missing from your post.
    >
    > If eventObj really is a String, then its length is 0.
    >
    > If eventObj isn't a String, the length reported by the receiving
    > method cannot be trusted here, and the JVM will be left in an unstable
    > state (and will eventually crash if you make a habit of this).
    >
    > /gordon
    >
    > --



    Thx for yor repyl gordon. The eventObject was my mistake. In my code
    snippet i tried to focus on the important lines in the code,
    eleminating everything unnecessary. Unfortunatelly i deleted the wrong
    function call. Instead of

    continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    jmid, eventObj, jStr);

    i call

    continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    jmid, jStr);

    Sorry for that mistake!
     
    , Apr 16, 2007
    #3
  4. On 16 Apr 2007 09:57:06 -0700, wrote:
    > continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    > jmid, jStr);


    So, how can you be certain that the code you've posted actually
    contains the error?

    Since the actual String creation and method call don't appear to be
    wrong, a logical conclusion is that the error is elsewhere. For
    example, almost any kind of memory corruption could result in this
    call subsequently failing in an erratic or unexplainable manner.

    There are important things missing from your post. How are prxParams
    (especially the jobj it holds) and the JNIEnv initialized? Since the
    native method is presumably called from a separate thread started from
    native code, you need to call AttachCurrentThread() somewhere or the
    JNIEnv won't be valid here.

    You should be cleaning up every object you create in this method.
    either with DeleteLocalRef(), or by wrapping the method in calls to
    Push/PopLocalFrame().

    Try to post a compilable example.

    /gordon

    --
     
    Gordon Beaton, Apr 16, 2007
    #4
  5. Guest

    On 16 Apr., 19:22, Gordon Beaton <> wrote:
    > On 16 Apr 2007 09:57:06 -0700, wrote:
    >
    > > continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    > > jmid, jStr);

    >
    > So, how can you be certain that the code you've posted actually
    > contains the error?
    >
    > Since the actual String creation and method call don't appear to be
    > wrong, a logical conclusion is that the error is elsewhere. For
    > example, almost any kind of memory corruption could result in this
    > call subsequently failing in an erratic or unexplainable manner.
    >
    > There are important things missing from your post. How are prxParams
    > (especially the jobj it holds) and the JNIEnv initialized? Since the
    > native method is presumably called from a separate thread started from
    > native code, you need to call AttachCurrentThread() somewhere or the
    > JNIEnv won't be valid here.
    >
    > You should be cleaning up every object you create in this method.
    > either with DeleteLocalRef(), or by wrapping the method in calls to
    > Push/PopLocalFrame().
    >
    > Try to post a compilable example.
    >
    > /gordon
    >
    > --



    Thx gordon. Your totally right with your advise. I added now all
    neccessary code parts.. I did some testing this morining and what i
    found out is pretty interesting.

    C:
    struct RxParams
    {
    XLhandle eventHandle;
    long portHandle;
    const char *callBackName;
    jobject caller;
    JNIEnv *env;
    }typedef RXPARAMS;


    JNIEXPORT jlong JNICALL Java_VectorXLDriverLib_setNotifier(JNIEnv
    *env, jclass jcls, jobject portHandle, jint queueLevel , jobject
    caller, jstring callBackName)
    {
    [...]

    RXPARAMS prxParams;

    prxParams.eventHandle = eventHandle;
    prxParams.portHandle = ph;
    prxParams.caller = caller;
    prxParams.env = env;
    prxParams.callBackName = (*env)->GetStringUTFChars(env,callBackName,
    0);

    listenCan(prxParams);
    }
    return xlStatus;
    }

    void listenCan(RXPARAMS par)
    {
    writeLog("In RxThread\n");
    unsigned int msgsrx = RECEIVE_EVENT_SIZE;
    jsize count;
    jmethodID jmid;
    jclass icls;
    jboolean continueListening = 1;

    char string[50];
    JAVAOBJECT eventObj; //object used for callBack to java

    RXPARAMS prxParams = par;


    JNIEnv *env = par.env;

    writeLog("Before get Structure XLCANEvent\n");
    // Klasse des aufrufenden Java Objektes ermitteln:
    icls = (*env)->GetObjectClass(env, prxParams.caller);

    writeLog("before getMID: icls: %02x\n", icls);
    jmid = (*env)->GetMethodID(env, icls,
    prxParams.callBackName,"(LXLCanEvent;Ljava/lang/String;)Z");

    writeLog("after getMID\n");
    if (jmid == 0){
    writeLog("jmid == NULL\n");
    }
    eventObj = CreatejObject(env, "XLCanEvent");


    writeLog("Before Get Field Ids\n");
    jfieldID jFldTransId = (*env)->GetFieldID(env, eventObj.jcls,
    "transid", "I");
    jfieldID jfldPortHandle = (*env)->GetFieldID(env,
    eventObj.jcls, "portHandle", "I");
    jfieldID jfldFlag = (*env)->GetFieldID(env, eventObj.jcls,
    "flags", "I");
    jfieldID jfldCanId = (*env)->GetFieldID(env, eventObj.jcls,
    "id", "J");


    jint test = 5;

    writeLog("CallBooleanMethod with Data\n");
    // Methode "intern" des aufrufenden Java Objektes aufrufen:
    (*env)->SetIntField(env, eventObj.ref, jFldTransId, test);
    (*env)->SetIntField(env, eventObj.ref, jfldPortHandle, test );
    (*env)->SetIntField(env, eventObj.ref, jfldFlag, test );
    (*env)->SetLongField(env, eventObj.ref, jfldCanId, test );


    const char *pWelt = "Hallo Welt";
    jstring jStr = NULL;
    jStr = (*env)->NewStringUTF(env, pWelt);


    if (jStr != NULL){
    jsize size = (*env)->GetStringUTFLength(env,jStr);
    writeLog("Is Not Null. Size: %d \n", size);
    }
    else
    writeLog("Is Null\n");


    continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    jmid, eventObj, jStr);

    #ifdef DEBUG
    writeLog("Listener has been terminated");
    #endif

    }

    JAVAOBJECT CreatejObject(JNIEnv *env , char * className)
    {
    jclass jcls;
    jfieldID jfid;
    jmethodID jmid;
    jobject jobj;

    JAVAOBJECT javaObj;

    javaObj.ref = NULL;
    javaObj.jcls = 0;


    javaObj.jcls = (*env)->FindClass(env, className);
    if (javaObj.jcls == NULL)
    {
    writeLog("Error FindClass\n");
    return javaObj;
    }

    //Get constructor id
    jmid = (*env)->GetMethodID(env, javaObj.jcls, "<init>","()V");
    if (jmid == NULL)
    {
    writeLog("Error GetMethodID\n");
    return javaObj;
    }

    //create new object
    javaObj.ref = (*env)->NewObject(env, javaObj.jcls, jmid);
    if (jobj == NULL)
    {
    writeLog("Error NewObject\n");
    return javaObj;
    }

    return javaObj;
    }




    Java Code:

    public class VectorCanLib implements Runnable{

    //Returns the Id of the gen
    public synchronized long registerListener(VectorXlLibraryNotifier
    callBack)
    {

    closeNotify = false;

    if(notifyThread == null){
    notifyThread = new Thread(this);
    notifyThread.start();
    }

    listeners.add(callBack);

    return 0;
    }


    public void run() {

    VectorXLDriverLib.setNotifier(portHandle, queueLevel, this,
    "internalNotifyCallback");

    System.out.println("Internal notifier closed");
    }


    private synchronized boolean internalNotifyCallback(XLCanEvent e,
    String obj)
    {
    //TODO: Alle abgespeicherten callbacks nacheinander benachrichtigen

    if(e != null){
    System.out.println("Received: TransID: " + e.transid + " PH "+
    e.portHandle +" CANID "+ e.id);
    }
    else{
    ;//System.out.println("null call received");
    }

    if(obj != null)
    {
    System.out.println(obj.length());
    System.out.println("object is not null : " + obj.toString());
    }

    if(closeNotify){
    System.out.println("CloseNotify is " + closeNotify);
    }
    return !closeNotify;

    }
    }

    public abstract class VectorXLDriverLib{

    [.....]


    public static native long setNotifier(XLPortHandle portHandle, int
    queueLevel, Object caller, String callBackName);

    static {
    try{
    System.load(System.getProperty("user.dir") + "\\" + "MyDll.dll");
    }
    catch(Exception e) {
    e.printStackTrace();
    }
    }

    public class XLCanEvent {
    public char channelIndex;
    public int transid; //internal use only
    public int portHandle; //internal use only
    public long id;/
    public int flags;
    }


    Now the example should contain everything neccessary. What i found out
    is that if i replace in the function listenCan()

    continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    jmid, eventObj, jStr);

    with

    continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    jmid, NULL, jStr);

    than the string obj will be correctyl given to java! Could it be that
    the eventObj overrides the string reference??? I changed nothing else
    in the code expect of these line!

    Thanks for your help in advance
     
    , Apr 17, 2007
    #5
  6. Guest

    On 17 Apr., 09:23, wrote:
    > On 16 Apr., 19:22, Gordon Beaton <> wrote:
    >
    >
    >
    > > On 16 Apr 2007 09:57:06 -0700, wrote:

    >
    > > > continueListening = (*env)->CallBooleanMethod(env, prxParams.jobj,
    > > > jmid, jStr);

    >
    > > So, how can you be certain that the code you've posted actually
    > > contains the error?

    >
    > > Since the actual String creation and method call don't appear to be
    > > wrong, a logical conclusion is that the error is elsewhere. For
    > > example, almost any kind of memory corruption could result in this
    > > call subsequently failing in an erratic or unexplainable manner.

    >
    > > There are important things missing from your post. How are prxParams
    > > (especially the jobj it holds) and the JNIEnv initialized? Since the
    > > native method is presumably called from a separate thread started from
    > > native code, you need to call AttachCurrentThread() somewhere or the
    > > JNIEnv won't be valid here.

    >
    > > You should be cleaning up every object you create in this method.
    > > either with DeleteLocalRef(), or by wrapping the method in calls to
    > > Push/PopLocalFrame().

    >
    > > Try to post a compilable example.

    >
    > > /gordon

    >
    > > --

    >
    > Thx gordon. Your totally right with your advise. I added now all
    > neccessary code parts.. I did some testing this morining and what i
    > found out is pretty interesting.
    >
    > C:
    > struct RxParams
    > {
    > XLhandle eventHandle;
    > long portHandle;
    > const char *callBackName;
    > jobject caller;
    > JNIEnv *env;
    >
    > }typedef RXPARAMS;
    >
    > JNIEXPORT jlong JNICALL Java_VectorXLDriverLib_setNotifier(JNIEnv
    > *env, jclass jcls, jobject portHandle, jint queueLevel , jobject
    > caller, jstring callBackName)
    > {
    > [...]
    >
    > RXPARAMS prxParams;
    >
    > prxParams.eventHandle = eventHandle;
    > prxParams.portHandle = ph;
    > prxParams.caller = caller;
    > prxParams.env = env;
    > prxParams.callBackName = (*env)->GetStringUTFChars(env,callBackName,
    > 0);
    >
    > listenCan(prxParams);
    > }
    > return xlStatus;
    >
    > }
    >
    > void listenCan(RXPARAMS par)
    > {
    > writeLog("In RxThread\n");
    > unsigned int msgsrx = RECEIVE_EVENT_SIZE;
    > jsize count;
    > jmethodID jmid;
    > jclass icls;
    > jboolean continueListening = 1;
    >
    > char string[50];
    > JAVAOBJECT eventObj; //object used for callBack to java
    >
    > RXPARAMS prxParams = par;
    >
    > JNIEnv *env = par.env;
    >
    > writeLog("Before get Structure XLCANEvent\n");
    > // Klasse des aufrufenden Java Objektes ermitteln:
    > icls = (*env)->GetObjectClass(env, prxParams.caller);
    >
    > writeLog("before getMID: icls: %02x\n", icls);
    > jmid = (*env)->GetMethodID(env, icls,
    > prxParams.callBackName,"(LXLCanEvent;Ljava/lang/String;)Z");
    >
    > writeLog("after getMID\n");
    > if (jmid == 0){
    > writeLog("jmid == NULL\n");
    > }
    > eventObj = CreatejObject(env, "XLCanEvent");
    >
    > writeLog("Before Get Field Ids\n");
    > jfieldID jFldTransId = (*env)->GetFieldID(env, eventObj.jcls,
    > "transid", "I");
    > jfieldID jfldPortHandle = (*env)->GetFieldID(env,
    > eventObj.jcls, "portHandle", "I");
    > jfieldID jfldFlag = (*env)->GetFieldID(env, eventObj.jcls,
    > "flags", "I");
    > jfieldID jfldCanId = (*env)->GetFieldID(env, eventObj.jcls,
    > "id", "J");
    >
    > jint test = 5;
    >
    > writeLog("CallBooleanMethod with Data\n");
    > // Methode "intern" des aufrufenden Java Objektes aufrufen:
    > (*env)->SetIntField(env, eventObj.ref, jFldTransId, test);
    > (*env)->SetIntField(env, eventObj.ref, jfldPortHandle, test );
    > (*env)->SetIntField(env, eventObj.ref, jfldFlag, test );
    > (*env)->SetLongField(env, eventObj.ref, jfldCanId, test );
    >
    > const char *pWelt = "Hallo Welt";
    > jstring jStr = NULL;
    > jStr = (*env)->NewStringUTF(env, pWelt);
    >
    > if (jStr != NULL){
    > jsize size = (*env)->GetStringUTFLength(env,jStr);
    > writeLog("Is Not Null. Size: %d \n", size);
    > }
    > else
    > writeLog("Is Null\n");
    >
    > continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    > jmid, eventObj, jStr);
    >
    > #ifdef DEBUG
    > writeLog("Listener has been terminated");
    > #endif
    >
    > }
    >
    > JAVAOBJECT CreatejObject(JNIEnv *env , char * className)
    > {
    > jclass jcls;
    > jfieldID jfid;
    > jmethodID jmid;
    > jobject jobj;
    >
    > JAVAOBJECT javaObj;
    >
    > javaObj.ref = NULL;
    > javaObj.jcls = 0;
    >
    > javaObj.jcls = (*env)->FindClass(env, className);
    > if (javaObj.jcls == NULL)
    > {
    > writeLog("Error FindClass\n");
    > return javaObj;
    > }
    >
    > //Get constructor id
    > jmid = (*env)->GetMethodID(env, javaObj.jcls, "<init>","()V");
    > if (jmid == NULL)
    > {
    > writeLog("Error GetMethodID\n");
    > return javaObj;
    > }
    >
    > //create new object
    > javaObj.ref = (*env)->NewObject(env, javaObj.jcls, jmid);
    > if (jobj == NULL)
    > {
    > writeLog("Error NewObject\n");
    > return javaObj;
    > }
    >
    > return javaObj;
    >
    > }
    >
    > Java Code:
    >
    > public class VectorCanLib implements Runnable{
    >
    > //Returns the Id of the gen
    > public synchronized long registerListener(VectorXlLibraryNotifier
    > callBack)
    > {
    >
    > closeNotify = false;
    >
    > if(notifyThread == null){
    > notifyThread = new Thread(this);
    > notifyThread.start();
    > }
    >
    > listeners.add(callBack);
    >
    > return 0;
    > }
    >
    > public void run() {
    >
    > VectorXLDriverLib.setNotifier(portHandle, queueLevel, this,
    > "internalNotifyCallback");
    >
    > System.out.println("Internal notifier closed");
    > }
    >
    > private synchronized boolean internalNotifyCallback(XLCanEvent e,
    > String obj)
    > {
    > //TODO: Alle abgespeicherten callbacks nacheinander benachrichtigen
    >
    > if(e != null){
    > System.out.println("Received: TransID: " + e.transid + " PH "+
    > e.portHandle +" CANID "+ e.id);
    > }
    > else{
    > ;//System.out.println("null call received");
    > }
    >
    > if(obj != null)
    > {
    > System.out.println(obj.length());
    > System.out.println("object is not null : " + obj.toString());
    > }
    >
    > if(closeNotify){
    > System.out.println("CloseNotify is " + closeNotify);
    > }
    > return !closeNotify;
    >
    > }
    >
    > }
    >
    > public abstract class VectorXLDriverLib{
    >
    > [.....]
    >
    > public static native long setNotifier(XLPortHandle portHandle, int
    > queueLevel, Object caller, String callBackName);
    >
    > static {
    > try{
    > System.load(System.getProperty("user.dir") + "\\" + "MyDll.dll");
    > }
    > catch(Exception e) {
    > e.printStackTrace();
    > }
    >
    > }
    >
    > public class XLCanEvent {
    > public char channelIndex;
    > public int transid; //internal use only
    > public int portHandle; //internal use only
    > public long id;/
    > public int flags;
    >
    > }
    >
    > Now the example should contain everything neccessary. What i found out
    > is that if i replace in the function listenCan()
    >
    > continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    > jmid, eventObj, jStr);
    >
    > with
    >
    > continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    > jmid, NULL, jStr);
    >
    > than the string obj will be correctyl given to java! Could it be that
    > the eventObj overrides the string reference??? I changed nothing else
    > in the code expect of these line!
    >
    > Thanks for your help in advance


    AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!! After i posted i saw my
    mistake!!!

    Instead of calling

    continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    > jmid, eventObj, jStr);


    i had to call

    continueListening = (*env)->CallBooleanMethod(env, prxParams.caller,
    > jmid, eventObj.ref, jStr);


    because eventObj is a structur, which contains the real obj:

    struct javaObject
    {
    jobject ref; //reference to the java object
    jclass jcls; //class id of the java obj
    }typedef JAVAOBJECT;


    OMG. What a stupid mistake....this costs me at least one day!!!
    Sometimes stupidity really hurts ;)

    Thanks gordon, without your hints i properly would continue searching
    the whole week;)
     
    , Apr 17, 2007
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jabel D. Morales - VMan of Mana

    Problems with JNI: calling a Java method from native method.

    Jabel D. Morales - VMan of Mana, Aug 1, 2003, in forum: Java
    Replies:
    1
    Views:
    4,805
    Joseph Millar
    Aug 1, 2003
  2. Kalpesh Modha

    JNI Strings and Calling a Java Method.

    Kalpesh Modha, Dec 12, 2003, in forum: Java
    Replies:
    0
    Views:
    2,768
    Kalpesh Modha
    Dec 12, 2003
  3. Kalpesh Modha

    JNI Strings and Calling a Java Method

    Kalpesh Modha, Dec 14, 2003, in forum: Java
    Replies:
    0
    Views:
    648
    Kalpesh Modha
    Dec 14, 2003
  4. Replies:
    5
    Views:
    10,429
    Gordon Beaton
    Oct 20, 2005
  5. Eyal
    Replies:
    2
    Views:
    486
Loading...

Share This Page