Pull to refresh

JNA: callbacks to Java

Reading time2 min
Views25K
Мне понадобилось подключить наш проект на Яве к старой библиотеке на C. Одной из проблем было, что эта библиотека требует регистрации колбеков (callbacks), которые вызывает по ходу работы, и которые, я хотел бы имплементировать на стороне Явы.

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
Tags:
Hubs:
+26
Comments24

Articles

Change theme settings