I am trying to generate java bindings through swig for these two c++ functions
C++ functions
void SetUserData(void* data);
void* GetUserData() const;
For completeness, here's another (simpler?) way to do it with JavaCPP. Assuming we have a GlobalData.h
file like this in C++:
class Data {
public:
JNIEnv* env;
jobject data;
Data(JNIEnv* env, jobject obj) : env(env), data(NULL) { }
~Data() { if (data != NULL) env->DeleteGlobalRef(data); }
void SetUserData(jobject obj) {
if (data != NULL) env->DeleteGlobalRef(data);
data = env->NewGlobalRef(obj);
}
jobject GetUserData() { return data; }
};
We can use it from Java this way:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include="GlobalData.h")
public class GlobalData {
static { Loader.load(); }
public static class Data extends Pointer {
public Data() { allocate(); }
private native @Raw(withEnv=true) void allocate();
public native void SetUserData(@Raw Object obj);
public native @Raw Object GetUserData();
}
public static void main(String[] args) {
Object someObject = new Object();
Data myData = new Data();
myData.SetUserData(someObject);
Object sameObject = myData.GetUserData();
System.out.println(someObject);
System.out.println(sameObject);
}
}
Where the output shows that someObject
and sameObject
point to the same object, for example:
java.lang.Object@7aa06577
java.lang.Object@7aa06577
You probably want to do:
%apply jobject { void* };
because %apply copies the typemaps defined on one C++ type to another C++ type. Object
is a Java type, not a C++ one so doesn't have any typemaps to be copied. jobject
on the other hand is the JNI equivalent.
Additionally assuming you want to have 'normal' GC semantics (i.e. not be required to retain whatever data you pass in) you'll need to do some more work, for example:
%module test
%{
#include "test.hh"
%}
%apply jobject { void * };
%typemap(in) void * {
void *old = getData();
if (old) JCALL1(DeleteGlobalRef, jenv, (jobject)old);
$1 = JCALL1(NewGlobalRef, jenv, $input);
}
%typemap(out) void * {
$result = (jobject)($1);
}
%include "test.hh"
This makes a new Global Reference for your data, which could be the only thing keeping it from getting freed by the GC.
Given a header file:
void setData(void *);
void *getData();
and an implementation:
#include "test.hh"
namespace {
void *d = nullptr;
}
void setData(void *d) {
::d = d;
}
void *getData() {
return d;
}
That is sufficient to allow:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
Object example = "HELLO";
test.setData(example);
System.out.println(test.getData());
}
}
to work correctly.
As written these typemaps are pretty ugly - they'll impact all usage of void *
. So if you really used this you would want to use %apply
or %clear
a second time to limit their impact. You could also name the arguments in the header file and use that to limit where the typemap gets applied.