Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
800 views
in Technique[技术] by (71.8m points)

c++ - Accessing a Java object in a Java object in C using JNI

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...