How to call go function by java JNI

Table of Contents

To use JNI to call the CreateRole function of the Teleport Go client, you need to expose this functionality through a Go shared library, following the steps below. The goal is to make the Go function callable from Java by wrapping it in a JNI-compatible interface.


1. Understand the Function Signature

The Go function you want to call has the signature:

func (c *Client) CreateRole(ctx context.Context, role types.Role) (types.Role, error)
  • ctx context.Context: The context for controlling request lifetime.
  • role types.Role: The role to create.
  • (types.Role, error): The created role or an error.

2. Expose the Functionality with a Wrapper

Create a Go wrapper function that simplifies the parameters and returns the result in a JNI-compatible format (like a C string).

Example Wrapper Code:

package main

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lteleport
#include <stdlib.h>
*/
import "C"

import (
    "context"
    "encoding/json"
    "github.com/gravitational/teleport/api/client"
    "github.com/gravitational/teleport/api/types"
    "unsafe"
)

//export CreateRole
func CreateRole(addr *C.char, name *C.char, roleSpecJSON *C.char) *C.char {
    addrStr := C.GoString(addr)
    nameStr := C.GoString(name)
    roleSpecStr := C.GoString(roleSpecJSON)

    // Parse the role specification from JSON
    var roleSpec types.RoleSpecV4
    if err := json.Unmarshal([]byte(roleSpecStr), &roleSpec); err != nil {
        return C.CString("Error parsing role specification: " + err.Error())
    }

    // Create a client
    client, err := client.New(client.Config{
        Addrs: []string{addrStr},
    })
    if err != nil {
        return C.CString("Error creating client: " + err.Error())
    }
    defer client.Close()

    // Create the role
    role, err := types.NewRole(nameStr, roleSpec)
    if err != nil {
        return C.CString("Error creating role object: " + err.Error())
    }

    createdRole, err := client.CreateRole(context.Background(), role)
    if err != nil {
        return C.CString("Error creating role: " + err.Error())
    }

    // Convert the created role to JSON
    createdRoleJSON, err := json.Marshal(createdRole)
    if err != nil {
        return C.CString("Error serializing created role: " + err.Error())
    }

    return C.CString(string(createdRoleJSON))
}

func main() {}

3. Compile the Go Shared Library

Build the shared library (.so) with the wrapper function:

go build -o libteleport.so -buildmode=c-shared main.go

This will generate:

  • libteleport.so: The shared library.
  • libteleport.h: The C header file to include in Java.

4. Java Code for JNI Integration

Write the Java code to load and call the shared library.

Define the Native Method

public class TeleportClient {
    static {
        System.loadLibrary("teleport"); // Loads libteleport.so
    }

    public native String createRole(String address, String name, String roleSpecJSON);

    public static void main(String[] args) {
        TeleportClient client = new TeleportClient();
        String address = "localhost:3025";
        String name = "example-role";
        String roleSpecJSON = "{\"allow\": {\"logins\": [\"admin\"]}, \"deny\": {}}";

        String response = client.createRole(address, name, roleSpecJSON);
        System.out.println("Response: " + response);
    }
}

Generate JNI Header

Generate the JNI header file:

javac TeleportClient.java
javah -jni TeleportClient

This creates a TeleportClient.h file. Ensure the method signature matches the Go CreateRole function.


5. Link JNI Header with Go

The generated JNI header will define a function signature like this:

JNIEXPORT jstring JNICALL Java_TeleportClient_createRole
  (JNIEnv *, jobject, jstring, jstring, jstring);

Ensure your Go code wraps this method signature if necessary.


6. Run the Java Program

  1. Ensure the libteleport.so is in your library path:
    export LD_LIBRARY_PATH=.
  2. Run the Java program:
    java TeleportClient

Considerations

  • Error Handling: Ensure all errors are handled and returned as meaningful strings.
  • Role Specification: Pass the roleSpecJSON in a format expected by the Go wrapper.
  • Memory Management: Free memory allocated by C.CString using C.free if needed to avoid memory leaks.
  • Platform: Ensure the library is compiled for the correct platform (Linux, macOS, or Windows).

Would you like further assistance with any specific part of this setup?

Comments |0|

Legend *) Required fields are marked
**) You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Category: 似水流年