Мне понадобилось подключить наш проект на Яве к старой библиотеке на 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