I am up with implementing my Java Native Interface functions in Golang using the golang C
lib.
Now I want to convert a jstring
to an UTF-8 string using the JNI function GetStringUTFChars
but I get an error when doing it. These are the steps I have done:
In my Java class (called MyClass) where I have defined the JNI method, I have:
public static native void print(String msg);
Using javah
, I have generated the .h
-file with the function defined in C language:
JNIEXPORT void JNICALL Java_com_mypackage_MyClass_print
(JNIEnv *, jclass, jstring);
Then, in my Go code I have the following code:
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)
}
When I build the go
file using:
go build -buildmode=c-shared -o libmyclass.dylib libmyclass.go
then I get the following error:
could not determine kind of name for C.GetStringUTFChars
How should I call the GetStringUTFChars
defined in the JNI spec so I then can print the string with fmt.println
?
EDIT 2
Removed "edit 1" since the procedure above was correct, it was just the LD_LIBRARY_PATH variable that was not set.
JNI functions like GetStringUTFChars
are function pointers and cannot be called directly from Go. You have to wrap the functions you need in a separate C file. e.g.
jx.c
#include <jni.h>
const char* jx_GetStringUTFChars(JNIEnv *env, jstring str, jboolean *isCopy) {
return (*env)->GetStringUTFChars(env, str, isCopy);
}
After creating a library from the C file, your Go file will look something like this:
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() {}
The reason why there is a separate C file just for the wrapper function is because of this clause in the documentation:
Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not contain any definitions, only declarations.