A possible solution may be the use of a dynamically allocated structure in the native code. For that to work, you have to allocate (for example, in the constructor) some memory that holds the structure. The address of that structure is passed back to the Java part and stored in the Java object. Then, for getValue
and setValue
, a parameter is added that holds the memory address of the allocated structure, you can then use for storing the value. When destroying the object, you have to free the memory manually.
Using your code, the native part may look like:
#include <cstdlib>
#include <jni.h>
#include "Test.h"
struct data {
int value;
};
JNIEXPORT void JNICALL Java_Test_setValue0(JNIEnv *, jobject, jlong address, jint newValue)
{
struct data *ptr = (struct data *)address;
ptr->value = newValue;
}
JNIEXPORT jint JNICALL Java_Test_getValue0(JNIEnv *, jobject, jlong address)
{
struct data *ptr = (struct data *)address;
return ptr->value;
}
JNIEXPORT jlong JNICALL Java_Test_construct0(JNIEnv *, jobject) {
struct data *ptr = (struct data *)malloc(sizeof(*ptr));
return (jlong)ptr;
}
JNIEXPORT void JNICALL Java_Test_destruct0(JNIEnv *, jobject, jlong address) {
struct data *ptr = (struct data *)address;
free(ptr);
}
And the Java part would then look like:
public class Test
{
static
{
Runtime.getRuntime().loadLibrary("JNITests");
}
private long address;
private native long construct0();
private native void destruct0(long address);
private native void setValue0(long address, int value);
private native int getValue0(long address);
public Test() {
this.address = this.construct0();
}
@Override
public void finalize() {
this.destruct0(this.address);
super.finalize();
}
public void setValue(int value) {
this.setValue0(this.address, value);
}
public int getValue() {
return this.getValue0(this.address);
}
public static void main(String[] args)
{
Test test1 = new Test();
test1.setValue(34);
Test test2 = new Test();
test2.setValue(23);
System.out.println(test1.getValue());
}
}
I renamed the native methods to introduce the address
parameter without API change.