0

I have a JNI class with methods init() work(), and cleanup(). On the C++ side I create an instance of a C++ class Foo during init(), then call some methods on it during work(), and finally delete it inside cleanup(). Right now I store instance of Foo as a global singleton on the C++ so that I can retrieve it from the different JNI calls. What I would really like to do is store a pointer to the Foo instance inside the jobject instance that gets passed to each JNI call, so that I can avoid having a global singleton and also so that I can support multiple instances of Foo. Is something like this possible?

Alex Flint
  • 6,040
  • 8
  • 41
  • 80
  • 2
    Possible http://stackoverflow.com/questions/337268/what-is-the-correct-way-to-store-a-native-pointer-inside-a-java-object(duplicate) – mkaes Jun 30 '14 at 14:12

3 Answers3

2

You can store a pointer to your C++ object as a Java class member. For example, in Java:

class Foo
{
    public long ptr = 0;

    public native void init();
    public native void work();
    public native void cleanup();
}

And in C++:

jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
{
    static jfieldID ptrFieldId = 0;

    if (!ptrFieldId)
    {
        jclass c = env->GetObjectClass(obj);
        ptrFieldId = env->GetFieldID(c, "ptr", "J");
        env->DeleteLocalRef(c);
    }

    return ptrFieldId;
}

class Foo
{
    /* ... */
};

extern "C"
{
    void Java_Foo_init(JNIEnv * env, jobject obj)
    {
        env->SetLongField(obj, getPtrFieldId(env, obj), (jlong) new Foo);
    }

    void Java_Foo_work(JNIEnv * env, jobject obj)
    {
        Foo * foo = (Foo *) env->GetLongField(obj, getPtrFieldId(env, obj));

        foo->work();
    }

    void Java_Foo_cleanup(JNIEnv * env, jobject obj)
    {
        Foo * foo = (Foo *) env->GetLongField(obj, getPtrFieldId(env, obj));

        delete foo;
    }
}
James M
  • 18,506
  • 3
  • 48
  • 56
1

Absolutely.

Create a Foo instance in JNI. Simply return the pointer (points to the instance created) as a jlong type. So you can use it as a handler later. Here is an example:

JNIEXPORT jlong JNICALL Java_com_example_init(JNIEnv *env, jobject thiz) {
   Foo* pFoo = new Foo();
   if (NULL == pFoo) {
       // error handling
   }

   pFoo->initialize();
   return reinterpret_cast<jlong>(pFoo);
}

JNIEXPORT void JNICALL Java_example_start(JNIEnv *env, jobject thiz,
jlong fooHandle) {
   Foo* pFoo = reinterpret_cast<Foo*>(fooHandle);
   pFoo->start();
}
Da Ha Song
  • 398
  • 5
  • 11
-1

You can do it with a long in java, however I would argue that its not a very good idea to put a pointer to some native memory address in an instance variable of a language that is expected to be operating in a sandbox. Its sloppy and it could be a exploit vector depending on what your doing.

I am guessing you are running into this problem because your native code is very close to your JNI code. If you structure your JNI layer as translation between your native code and Java, you may find it easier to work with.

Alex Barker
  • 4,316
  • 4
  • 28
  • 47