Мне понадобилось подключить наш проект на Яве к старой библиотеке на C. Одной из проблем было, что эта библиотека требует регистрации колбеков (callbacks), которые вызывает по ходу работы, и которые, я хотел бы имплементировать на стороне Явы.
JNI позволяет это всё делать, но муторно. Есть прекрасная библиотека JNA как замена JNI я хотел воспользоваться ей.
К сожалению сайт JNA сейчас пуст — они переезжают с сервера на сервер, статьи по JNA не показывают пример callbacks, поэтому пришлось повозиться немного, чтобы сделать работающий пример.
Этот пример и хочу показать — может кому то приходится.
Начинаем со стороны C:
my.h
my.c
Компилируем:
и кладём куда то, куда указывает LD_LIBRARY_PATH
Создаём интерфейс для callback и интерфейс, который представляет нашу C библиотеку:
MyCallBack.java
MyLib.java
И всё! Никаких странных сигнатур или генерации header files, знакомых из JNI!
Вызывается это так:
Единственное что неприятно, о, что в колбеке может быть только один метод, т.е. если у меня десять колбеков, мне надо создавать (и регистрировать!) десять таких классов. Но можно сделать один ява класс, который будет содержать эту всю логику — он будет принимать один интерфейс с многоми методами для колбеков и «переводить» его на язык многих классов имплементирующих интерфейс Callback
UPD:
ЖЖ юзер letu4i пишет:
Хотел заметить, что реализация JNA немного отличается в разных JVM. Например в Cassandra был баг из-за чрезмерного полагания на JNA:
issues.apache.org/jira/browse/CASSANDRA-1760
Если не трудно, добавьте disclaimer что использовать надо аккуратно.
P.S. Баг проявлялся на JRockit JVM
JNI позволяет это всё делать, но муторно. Есть прекрасная библиотека JNA как замена JNI я хотел воспользоваться ей.
К сожалению сайт JNA сейчас пуст — они переезжают с сервера на сервер, статьи по JNA не показывают пример callbacks, поэтому пришлось повозиться немного, чтобы сделать работающий пример.
Этот пример и хочу показать — может кому то приходится.
Начинаем со стороны C:
my.h
typedef void (*callback)(char *, char*);
int myfunc(char *);
void registerCallback(callback myc);
my.c
#include <string.h>
#include "my.h"
static callback c;
int myfunc(char *name) {
(*c)("received", name);
return strlen(name);
}
void registerCallback(callback myc) {
c = myc;
}
Компилируем:
gcc -c -fPIC -m32 -g my.c -omy.o gcc -m32 -shared -g my.o -o ./libmy.so |
и кладём куда то, куда указывает LD_LIBRARY_PATH
Создаём интерфейс для callback и интерфейс, который представляет нашу C библиотеку:
MyCallBack.java
import com.sun.jna.Callback;
public class MyCallBack implements Callback {
public void callback (String param1, String param2) {
System.out.println(param1+" "+param2);
}
}
MyLib.java
import com.sun.jna.Library;
public interface MyLib extends Library {
int myfunc(String name);
void registerCallback(MyCallBack myc);
}
И всё! Никаких странных сигнатур или генерации header files, знакомых из JNI!
Вызывается это так:
import com.sun.jna.Native;
public class App {
public static void main(String[] args) {
MyLib lib = (MyLib) Native.loadLibrary("my", MyLib.class);
lib.registerCallback(new MyCallBack());
System.out.println(lib.myfunc("test1"));
}
}
Единственное что неприятно, о, что в колбеке может быть только один метод, т.е. если у меня десять колбеков, мне надо создавать (и регистрировать!) десять таких классов. Но можно сделать один ява класс, который будет содержать эту всю логику — он будет принимать один интерфейс с многоми методами для колбеков и «переводить» его на язык многих классов имплементирующих интерфейс Callback
UPD:
ЖЖ юзер letu4i пишет:
Хотел заметить, что реализация JNA немного отличается в разных JVM. Например в Cassandra был баг из-за чрезмерного полагания на JNA:
issues.apache.org/jira/browse/CASSANDRA-1760
Если не трудно, добавьте disclaimer что использовать надо аккуратно.
P.S. Баг проявлялся на JRockit JVM