-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
how to pass go func to jvm #75
Comments
They way I've done this in tha past is to create a class in java that implements the interface and declare all the methods native (or at least the ones you are interested in). Then provide the go implementations using registernatives. Please see Oracle's JNI documentation on how to do this. https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html The implementing funnctionns are passed the object so you can keep track of this on the Go side. |
Hey, thanks for your reply and sorry for my late response. Can As an example: I have the following class, which, as you suggested, implements the said function interface: package shared.server;
import java.util.function.Function;
public class RouteHandlerNative implements Function<String, String> {
private String path;
public RouteHandlerNative(String path) {
this.path = path;
}
public native String apply(String arg0);
} Now can I do the following, but for an instance of func applyTest(arg0 string) string {
return ""
}
rhn_obj, err := env.NewObject("shared/server/RouteHandlerNative", []string{"/test"})
env.RegisterNative("shared/server/RouteHandlerNative", "apply", jnigi.Object, []interface{}{}, applyTest) // <-- use for rhn_obj instead? Here's a little context for what I am trying: I'm trying to provide a Java library that can be used from go (and other languages), but accepts custom function implementations from the host language (go, and other languages). The domain is a webserver (java shared lib) for which route handlers can be registered from host languages. The poc includes handlers that handle requests and respond with a response, in this case a string, hence the interface I hope that clarifies my needs and request. |
Hi, in your example you are on the right direction but you can't use go types in your native function call back, JNI uses C, so you need to convert from the C types to go types in your call back. So something like (just going off old code of mine): /*
#include<stdint.h>
extern uintptr_t go_callback_RouteHandlerNativeApply(void *env, uintptr_t obj, uintptr_t arg0)
*/
import"C"
//export go_callback_RouteHandlerNativeApply
func go_callback_RouteHandlerNativeApply(env unsafe.Pointer, obj uintptr, arg0 uintptr) uintptr Then you can use the C function in the last argument to JNIGI RegisterNative. In your callback you need to convert the argument to a go string, call your go function and convert the go string returned to a java string and return. You need a good understanding of how Cgo works https://pkg.go.dev/cmd/cgo . Maybe if you get it working you could submit an example to the project! |
Hi and thanks for the reference. I followed your advice using JNIEXPORT jstring JNICALL Java_shared_server_Server_handle_1request_1external
(JNIEnv *, jclass, jint, jstring); This is the corresponding go function: func handle_request_external(env unsafe.Pointer, obj uintptr, fn_id uintptr, raw_request_ptr uintptr) *jnigi.ObjectRef {
println(fn_id, raw_request_ptr)
req_ptr := unsafe.Pointer(raw_request_ptr)
req_string_ptr := (*string)(req_ptr)
request := *req_string_ptr
println(request)
var env_val *jnigi.Env = (*jnigi.Env)(env)
resp, _ := env_val.NewObject("java/lang/String", []byte("test"))
return resp
} I'm now trying to register the function as a native method: env.RegisterNative("shared/server/Server", "Java_shared_server_Server_handle_1request_1external", jnigi.Object, []interface{}{}, handle_request_external)
//or
env.RegisterNative("shared/server/Server", "handle_request_external", jnigi.Object, []interface{}{}, handle_request_external) Both variants result in the following error: panic: interface conversion: interface {} is func(unsafe.Pointer, uintptr, uintptr, uintptr) *jnigi.ObjectRef, not unsafe.Pointer
goroutine 1 [running, locked to thread]:
tekao.net/jnigi.(*Env).RegisterNative(0x4000062040, {0x4bf675?, 0x400004ff08?}, {0x4c4a7a, 0x33}, {0x4df338?, 0x4ded5c}, {0x400004fee0, 0x0, 0x200000003?}, ...) I assume the signature do not match somehow, but do you have any directions from here? |
Okay so following up, I researched some more and came a little further. Here's the current state and I feel like I'm close: With headers: #include<jni.h>
#include <stdint.h>
extern uintptr_t handle_request_external(void *env, uintptr_t obj, uintptr_t fn_id, uintptr_t raw_request_ptr); /*
#include<server.h>
*/
import "C"
//export handle_request_external
func handle_request_external(env unsafe.Pointer, obj uintptr, raw_fn_id uintptr, raw_request_ptr uintptr) uintptr {
req_ptr := unsafe.Pointer(raw_request_ptr)
request := *(*string)(req_ptr)
fn_id := int32(raw_fn_id)
route := routes[fn_id]
response := route.Handler(request)
println(response)
var env_val *jnigi.Env = jnigi.WrapEnv(env)
resp, _ := env_val.NewObject("java/lang/String", []byte(response))
return uintptr(unsafe.Pointer(resp))
}
...
env.RegisterNative("shared/server/Server", "handle_request_external", jnigi.ObjectType("java/lang/String"), []interface{}{jnigi.Int, "java/lang/String"}, C.handle_request_external) Everything works, so the native
with some gibbery core dumps I cannot quiet understand (cannot find the c program in order to use |
Hi! Sorry about the delay real life things... The first problem I see is you are trying to derefernce a pointer from Java as a Go string It might also be better for the |
Hi! I'm currently doing a PR to increase test coverage of the module. There is an test for RegisterNative that does what you were asking above if you are still interested. See commit: de58019 |
Hi I wanted to ask how it is possible to pass a go func as an implementation to an object in JVM that implements the
java.util.function.Function<String,String>
interface.Is there a way and if yes, what steps do I need for that?
I have tried the following attempt:
This of course fails, because there is no
<init>
ctor for an interface. My goal is to provide an implementation in go for that interface.The text was updated successfully, but these errors were encountered: