timob / jnigi

Golang Java JNI library
BSD 2-Clause "Simplified" License
166 stars 44 forks source link

How registerNative method use? #58

Closed GrapeBaBa closed 2 years ago

GrapeBaBa commented 2 years ago

I want to register a Go function as a java native method, the program not throw error, but execution result not as expect.

package main

/*
    #include <stdlib.h>

    extern void Test(_GoString_ arg1,_GoString_ arg2);

*/
import "C"
import (
    "fmt"
    "log"
    "runtime"
    "unsafe"

    "tekao.net/jnigi"
)

var A map[string]string

func init() {
    A = make(map[string]string)
}

var env *jnigi.Env
var jvm *jnigi.JVM

type GoString string

func (g *GoString) ConvertToGo(obj *jnigi.ObjectRef) error {
    defer env.DeleteLocalRef(obj)
    var goBytes []byte
    if err := obj.CallMethod(env, "getBytes", &goBytes); err != nil {
        return err
    }
    *g = GoString(goBytes)
    return nil
}

func (g *GoString) ConvertToJava() (obj *jnigi.ObjectRef, err error) {
    return env.NewObject("java/lang/String", []byte(string(*g)))
}

func (g *GoString) GetClassName() string {
    return "java/lang/String"
}

func (g *GoString) IsArray() bool {
    return false
}

type TestFunc func(string, string)

//export Test
func Test(key string, value string) {
    fmt.Println(key)
    fmt.Println(value)
    A[key] = value
    fmt.Println(A[key])
}

func main() {
    C.Test("A", "b")

    println(A["A"])
    if err := jnigi.LoadJVMLib("/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/server/libjvm.dylib"); err != nil {
        log.Fatal(err)
    }
    runtime.LockOSThread()
    jarPath := "/Users/kaichen/Documents/projects/jni-java-test/target/jni-java-test-1.0-SNAPSHOT.jar"
    var err error
    jvm, env, err = jnigi.CreateJVM(jnigi.NewJVMInitArgs(false, true, jnigi.JNI_VERSION_1_8, []string{"-Xcheck:jni", "-Xrs", fmt.Sprintf("-Djava.class.path=%s", jarPath)}))
    if err != nil {
        log.Fatal(err)
    }

    var a TestFunc
    a = Test
    err = env.RegisterNative("abc/Test", "put", jnigi.Void, []interface{}{"java/lang/String", "java/lang/String"}, unsafe.Pointer(&a))
    if err != nil {
        log.Fatal(err)
    }
    test := jnigi.NewObjectRef("abc/Test")
    if err != nil {
        log.Fatal(err)
    }

    for i := 0; i < 12; i++ {
        _ = test.CallMethod(env, "put", nil, GoString("B"), GoString("a"))
    }
    println(A["B"])
    //world, err := env.NewObject("java/lang/String", []byte("World!"))
    //if err != nil {
    //  log.Fatal(err)
    //}
    //
    //greeting := jnigi.NewObjectRef("java/lang/String")
    //err = hello.CallMethod(env, "concat", greeting, world)
    //if err != nil {
    //  log.Fatal(err)
    //}
    //
    //var goGreeting []byte
    //err = greeting.CallMethod(env, "getBytes", &goGreeting)
    //if err != nil {
    //  log.Fatal(err)
    //}
    //
    //// Prints "Hello World!"
    //fmt.Printf("%s\n", goGreeting)
    //
    if err = jvm.Destroy(); err != nil {
        log.Fatal(err)
    }
}
package abc;

/**
 * Created by IntelliJ IDEA.
 * Author: kaichen
 * Date: 2022/7/16
 * Time: 21:17
 */
public class Test {
    public native void put(String key, String value);
}
GrapeBaBa commented 2 years ago

there is no print when execute callMethod, the map also no change

timob commented 2 years ago

Try passing C.Test to RegisterNative as the last argument. This should work.

GrapeBaBa commented 2 years ago

@timob It not works for me. We now used c++ code to call registerNative.