I have no problem with simple callbacks when free function passed as parameter to another, thanks to @flexo.
But assume bit more difficult C interface:
typedef struct
{
int id;
const char* name;
} Item;
typedef struct
{
int value;
Items_Callback callback;
void *context;
} Items_Call;
typedef int (*Items_Callback)(const Item *item, void *context);
int Items_create(const Item *item, Items_Call *call) {
...
call->callback(item, call->context);
...
}
I intent to generate some nice Java wrapper for code like this. I assume to have as result
class Item {
public int id;
public String name;
}
class Items_Call {
public int value;
public Object context;
public Interface callback;
public void setInterface(Interface i){ callback=i; };
}
public interface Interface {
public int Items_Callback(Item item, Object context);
}
int Items_create(Item item, Items_Call call) {
...
call.callback.Items_Callback(item, call.context);
...
}
I realize that SWIG have some problem with generation of pure Java interfaces, but I believe it's not major problem. The problem is I have no idea how to reinterpret such nested structure to acceptable Java code.
Not SWIG, but the following works with JavaCPP (which does not come with the kind of overhead JNA has, and works wherever JNI works):
// items.h
typedef struct
{
int id;
const char* name;
} Item;
typedef int (*Items_Callback)(const Item *item, void *context);
typedef struct
{
int value;
Items_Callback callback;
void *context;
} Items_Call;
int Items_create(const Item *item, Items_Call *call) {
// ...
call->callback(item, call->context);
// ...
return 0;
}
And in Java:
import com.googlecode.javacpp.*;
import com.googlecode.javacpp.annotation.*;
@Platform(include="items.h")
public class Items {
static { Loader.load(); }
public static class Item extends Pointer {
public Item() { allocate(); }
private native void allocate();
public native int id(); public native Item id(int id);
@Cast("const char*")
public native BytePointer name(); public native Item name(BytePointer name);
}
public static class Items_Callback extends FunctionPointer {
protected Items_Callback() { allocate(); }
private native void allocate();
public native int call(@Const Item item, Pointer context);
}
public static class Items_Call extends Pointer {
public Items_Call() { allocate(); }
private native void allocate();
public native int value(); public native Items_Call value(int value);
public native Pointer context(); public native Items_Call context(Pointer context);
public native Items_Callback callback(); public native Items_Call callback(Items_Callback value);
public void setInterface(Items_Callback i) { callback(i); }
}
public static native void Items_create(Item item, Items_Call call);
public static void main(String[] args) {
BytePointer s = new BytePointer("Hello");
Item i = new Item();
i.id(42);
i.name(s);
Items_Callback cb = new Items_Callback() {
public int call(Item item, Pointer context) {
System.out.println(item.id() + " " + item.name().getString());
return 0;
}
};
Items_Call ic = new Items_Call();
ic.callback(cb);
Items_create(i, ic);
// if we remove these references, the GC may prematurely deallocate them
s.deallocate();
cb.deallocate();
}
}
Which outputs the expected result:
42 Hello
Disclaimer: I'm the author of JavaCPP :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With