Как мне вызвать функцию Java Native Interface C из моего кода Go? - PullRequest
0 голосов
/ 11 ноября 2018

Я реализую свои функции нативного интерфейса Java в Golang, используя golang C lib.
Теперь я хочу преобразовать jstring в строку UTF-8, используя функцию JNI GetStringUTFChars, но при этом я получаю ошибку. Вот шаги, которые я сделал:

В моем классе Java (называемом MyClass), где я определил метод JNI, у меня есть:

public static native void print(String msg);

Используя javah, я сгенерировал .h -файл с функцией, определенной на языке C:

JNIEXPORT void JNICALL Java_com_mypackage_MyClass_print
  (JNIEnv *, jclass, jstring);

Тогда в моем коде Go у меня есть следующий код:

package main

// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin
/*
#include <jni.h>
*/
import "C"

//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {

    _ = C.GetStringUTFChars(env, str, 0)

}

Когда я создаю файл go, используя:
go build -buildmode=c-shared -o libmyclass.dylib libmyclass.go
тогда я получаю следующую ошибку:

could not determine kind of name for C.GetStringUTFChars

Как мне вызвать GetStringUTFChars, определенный в JNI spec , чтобы затем я мог напечатать строку с fmt.println?

РЕДАКТИРОВАТЬ 2
Удалено «edit 1», так как процедура выше была правильной, это была просто переменная LD_LIBRARY_PATH, которая не была установлена.

1 Ответ

0 голосов
/ 12 ноября 2018

Функции JNI, такие как GetStringUTFChars, являются указателями на функции и не могут быть вызваны напрямую из Go. Вы должны обернуть нужные вам функции в отдельный C-файл. например,

jx.c

#include <jni.h>

const char* jx_GetStringUTFChars(JNIEnv *env, jstring str, jboolean *isCopy) {
    return (*env)->GetStringUTFChars(env, str, isCopy);
}

После создания библиотеки из файла C ваш файл Go будет выглядеть примерно так:

package main

/*
#cgo CFLAGS: -I/usr/java/jdk1.8.0_162/include/ -I/usr/java/jdk1.8.0_162/include/linux/
#cgo LDFLAGS: -L${SRCDIR}/ -ljx

#include "jx.h"
*/
import "C"
import (
    "fmt"
)

//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
    s := C.jx_GetStringUTFChars(env, str, (*C.jboolean)(nil))
    fmt.Println(C.GoString(s))
}

func main() {}

Причина, по которой существует отдельный файл C только для функции-обертки, заключается в следующем пункте документации:

Использование // экспорта в файл накладывает ограничение на преамбулу: поскольку он копируется в два разных выходных файла C, он не должен содержать никаких определений, только объявления.

...