5

I'm relatively new to JNI and have gotten down the basics of messing with integers and arrays in Java objects using JNI. Now I'm trying to modify/access a Java object within a Java object.

I've been searching on the internet and on Stack Overflow and have yet to find out how to do this.

Here's the example.

In Java:

public class ObjectOne
{
    private byte[] buff;
    ...
    ...
}

public class ObjectTwo
{
    private ObjectOne obj;
    ...
    ...
}

In JNI, how do I access "buff" from ObjectOne through ObjectTwo? I tried something like this...

JNIEXPORT void JNICALL Java_accessBuffThroughObjectTwo(JNIEnv *env, jobject obj, jobject objectTwo)
{
    jclass clazz;
    jclass bufferClazz;
    jobject bufferJObject;

    clazz = (*env)->GetObjectClass(env, objectTwo);
    fid = (*env)->GetFieldID(env, clazz, "obj", "Ljava/lang/Object;");
    bufferJObject = (*env)->GetObjectField(env, javascsicommand, fid);
    bufferClazz = (*env)->GetObjectClass(env, bufferJObject);  <-- Fails here for Access Violation
    fid = (*env)->GetFieldID(env, bufferClazz, "buff", "[B");
}

Any help on what I'm doing wrong?

7
  • First step is to check each JNI call to see if it is failing. Second: what is javascsicommand? Commented Aug 3, 2012 at 22:51
  • I believe you're passing the wrong value for the obj instance to GetObjectField. See the correct descriptor: jobject GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID); Commented Aug 4, 2012 at 2:55
  • Perhaps you meant to pass objectTwo rather than javascsicommand? Commented Aug 4, 2012 at 2:58
  • You cannot access the private fields of the other object. You need to provide getter, change access right keyword, or open the access runtime. Commented Aug 5, 2012 at 8:57
  • @qrtt1 Yes you can access private fields using JNI. Commented Aug 6, 2012 at 13:22

1 Answer 1

15

When trying your code you could easily add some assertions like this:

JNIEXPORT void JNICALL Java_accessBuffThroughObjectTwo(JNIEnv *env, jobject obj,  jobject objectTwo) {
    jclass clazz;
    jclass bufferClazz;
    jobject bufferJObject;
    jfieldID fid;

    clazz = (*env)->GetObjectClass(env, objectTwo);
    assert(clazz != NULL);
    fid = (*env)->GetFieldID(env, clazz, "obj", "Ljava/lang/Object;");
    assert(fid != NULL);
    bufferJObject = (*env)->GetObjectField(env, javascsicommand, fid);
    assert(bufferJObject != NULL);
    bufferClazz = (*env)->GetObjectClass(env, bufferJObject);
    assert(bufferClazz != NULL);
    fid = (*env)->GetFieldID(env, bufferClazz, "buff", "[B");
    assert(fid != NULL);
}

Doing so you will first see that the first fid will be NULL. That is because the ObjectTwo class does not have any fields of type java.lang.Object. You should change the line to look like this (but add the correct packages instead of com/package):

fid = (*env)->GetFieldID(env, clazz, "obj", "Lcom/package/ObjectOne;");

If you run again you will find that the fid is no longer null and the assertion will pass.

As others have suggested I believe that the javascsicommand should be objectTwo.

Now the next place where the assertion will fail is on bufferJObject. That is because the field exists but the object is NULL and if you check your java code you will notice that the obj field is never instantiated and is null.

Change your java code to something like this:

public class ObjectTwo
{
    private ObjectOne obj = new ObjectOne();
    ...
    ...
}

You will now pass the assertion and even pass all other assertions.

To summarize you were accessing a null object and trying to invoke reflection on it:

bufferClazz = (*env)->GetObjectClass(env, bufferJObject); <-- The bufferJObject was NULL
Sign up to request clarification or add additional context in comments.

4 Comments

thanks for this detailed response. I will definitely utilize the assertions and check for NULL. I think you hit the nail on the head when you were talking about accessing a null object. I think that's what's giving me the access violation
@user1575243 If you think that my answer was useful then please mark the answer as accepted!
@user1575243 If people like myself spend some time to set up coding environments, start debugging sessions and try to solve other peoples problems then the least you can expect from them is that they accept answers that they find useful...
Sorry about this. I didn't know that accepting answers was so valued. Answer accepted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.