如何从Go代码中调用Java本机接口C函数?

时间:2018-11-11 20:15:32

标签: c go java-native-interface cgo javah

我正在使用golang C lib在Golang中实现Java Native Interface函数。
现在,我想使用JNI函数jstringGetStringUTFChars转换为UTF-8字符串,但是这样做时出现错误。这些是我已经完成的步骤:

在我定义了JNI方法的Java类(称为MyClass)中,我有:

public static native void print(String msg);

我使用javah用C语言定义的函数生成了.h文件:

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

我应该如何调用JNI spec中定义的GetStringUTFChars,这样才能使用fmt.println打印字符串?

编辑2
由于上面的步骤正确,因此删除了“ edit 1”,只是未设置LD_LIBRARY_PATH变量。

1 个答案:

答案 0 :(得分:1)

GetStringUTFChars这样的JNI函数是函数指针,不能直接从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文件是因为文档中的以下子句:

  

在文件中使用// export会对序言进行限制:由于将其复制到两个不同的C输出文件中,因此它不得包含任何定义,而只能包含声明。