jnigi

package module
v0.0.0-...-5a2f360 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2024 License: BSD-2-Clause Imports: 9 Imported by: 0

README

JNIGI

JNI Go Interface.

A package to access Java from Go code. Can be used from a Go executable or shared library. This allows for Go to initiate the JVM or Java to start a Go runtime respectively.

Go Reference Actions

Install

# In your apps Go module directory
go get tekao.net/jnigi

# Add flags needed to include JNI header files, change this as appropriate for your JDK and OS
export CGO_CFLAGS="-I/usr/lib/jvm/default-java/include -I/usr/lib/jvm/default-java/include/linux"

# build your app
go build

The compilevars.sh (compilevars.bat on Windows) script can help setting the CGO_CFLAGS environment variable.

Finding JVM at Runtime

The JVM library is dynamically linked at run time. Use the LoadJVMLib(jvmLibPath string) error function to load the shared library at run time. There is a function AttemptToFindJVMLibPath() string to help to find the library path.

Status

Testing

Most of the code has tests. To run the tests using docker:

# get source
git clone https://github.com/timob/jnigi.git

cd jnigi

# build image
docker build -t jnigi_test .

# run tests
docker run jnigi_test
Uses

Has been used on Linux/Windows/MacOS (amd64) Android (arm64) multi threaded apps.

Note about using on Windows

Because of the way the JVM triggers OS exceptions during CreateJavaVM, which the Go runtime treats as unhandled exceptions, the code for the Go runtime needs to be changed to allow the JVM to handle the exceptions. See https://github.com/timob/jnigi/issues/31#issuecomment-1668914368 for how to do this.

Example

package main

import (
    "fmt"
    "tekao.net/jnigi"
    "log"
    "runtime"
)

func main() {
    if err := jnigi.LoadJVMLib(jnigi.AttemptToFindJVMLibPath()); err != nil {
        log.Fatal(err)
    }

    runtime.LockOSThread()
    jvm, env, err := jnigi.CreateJVM(jnigi.NewJVMInitArgs(false, true, jnigi.DEFAULT_VERSION, []string{"-Xcheck:jni"}))
    if err != nil {
        log.Fatal(err)
    }

    hello, err := env.NewObject("java/lang/String", []byte("Hello "))
    if err != nil {
        log.Fatal(err)
    }

    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)
    }
}

Documentation

Overview

JNIGI (Java Native Interface Go Interface)

A package to access Java from Go code.

All constructor and method call functions convert parameter arguments and return values.

Arguments are converted from Go to Java if:

  • The type is Go built in type and there is an equivalent Java "primitive" type.
  • The type is a slice of such a Go built in type.
  • The type implements the ToJavaConverter interface

Return values are converted from Java to Go if:

  • The type is a Java "primitive" type.
  • The type is a Java array of a "primitive" type.
  • The type implements the ToGoConverter interface

Go Builtin to/from Java "primitive":

bool			boolean
byte			byte
int16			short
uint16			char
int				int (also int32 -> int)
int64			long
float32			float
float64			double

Index

Constants

View Source
const (
	JNI_VERSION_1_2 = C.JNI_VERSION_1_2
	JNI_VERSION_1_4 = C.JNI_VERSION_1_4
	JNI_VERSION_1_6 = C.JNI_VERSION_1_6
	JNI_VERSION_1_8 = C.JNI_VERSION_1_8
	JNI_VERSION_9   = C.JNI_VERSION_9
	JNI_VERSION_10  = C.JNI_VERSION_10

	DEFAULT_VERSION = JNI_VERSION_1_6
)
View Source
const (
	Void = Type(1 << iota)
	Boolean
	Byte
	Char
	Short
	Int
	Long
	Float
	Double
	Object
	Array
)

Variables

This section is empty.

Functions

func AttemptToFindJVMLibPath

func AttemptToFindJVMLibPath() string

AttemptToFindJVMLibPath tries to find the full path to the JVM shared library file

func CreateJVM

func CreateJVM(jvmInitArgs *JVMInitArgs) (*JVM, *Env, error)

CreateJVM calls JNI CreateJavaVM and returns references to the JVM and the initial environment. Use NewJVMInitArgs to create jvmInitArgs.

Must call runtime.LockOSThread() first.

func LoadJVMLib

func LoadJVMLib(jvmLibPath string) error

LoadJVMLib loads libjvm.so as specified in jvmLibPath

func UseJVM

func UseJVM(pvm unsafe.Pointer, penv unsafe.Pointer, thiz unsafe.Pointer) (*JVM, *Env)

UseJVM initialized jnigi with an existing JVM.

This is important for Android, where the existing JVM must be used when running inside an Android app--i.e. Go code built as a shared library.

An existing JVM may be obtained through a JNI call made by the JVM after System.loadLibrary:

JNIEXPORT void JNICALL Java_foo_bar_Baz_00024_funcName(JNIEnv *env, jobject thiz) {
  // Pass env, thiz and the result of (*env)->GetJavaVM() into Go, then UseJVM()
}

If 'thiz' is specified, its class loader will be used to find non-system classes. This should pick up custom classes, as well as libraries from dependencies { } in build.gradle.

Parameters can also be derived from the JNI_OnLoad() call made during System.loadLibrary(). In this case, 'thiz' should be a custom class in order to retrieve a useful class loader.

Types

type ArrayRef

type ArrayRef struct {
	*ObjectRef
	Type
}

ArrayRef just disables auto conversion of Java arrays to Go slices

func NewArrayRef

func NewArrayRef(t Type) *ArrayRef

func (*ArrayRef) ConvertToGo

func (a *ArrayRef) ConvertToGo(obj *ObjectRef) error

Just hold on to the reference to the array jobject

func (*ArrayRef) GetType

func (a *ArrayRef) GetType() Type

type ByteArray

type ByteArray struct {
	// contains filtered or unexported fields
}

ByteArray holds a JNI JbyteArray

func (*ByteArray) CopyBytes

func (b *ByteArray) CopyBytes(env *Env) []byte

CopyBytes creates a go slice of bytes of same length as byte array, calls GetCritical, copies byte array into go slice, calls ReleaseCritical, returns go slice.

func (*ByteArray) GetCritical

func (b *ByteArray) GetCritical(env *Env) []byte

GetCritical calls JNI GetPrimitiveArrayCritical

func (*ByteArray) GetObject

func (b *ByteArray) GetObject() *ObjectRef

GetObject returns byte array as *ObjectRef.

func (*ByteArray) ReleaseCritical

func (b *ByteArray) ReleaseCritical(env *Env, bytes []byte)

GetCritical calls JNI ReleasePrimitiveArrayCritical

func (*ByteArray) SetObject

func (b *ByteArray) SetObject(o *ObjectRef)

SetObject sets byte array from o.

type ClassInfoGetter

type ClassInfoGetter interface {
	GetClassName() string
	IsArray() bool
}

ClassInfoGetter is implemented by *ObjectRef, *CastedObjectRef to get type info for object values.

type ClassLoaderRef

type ClassLoaderRef struct {
	// contains filtered or unexported fields
}

A reference to a class loader object

type Env

type Env struct {
	ExceptionHandler ExceptionHandler
	// contains filtered or unexported fields
}

Env holds a JNIEnv value. Methods in this package often require an *Env pointer to specify the JNI Env to run in, so it might be good to store the Env as a package variable.

func WrapEnv

func WrapEnv(envPtr unsafe.Pointer) *Env

WrapEnv wraps an JNI Env value in an Env

func (*Env) CallStaticMethod

func (j *Env) CallStaticMethod(className string, methodName string, dest interface{}, args ...interface{}) error

CallStaticMethod calls static method methodName in class className with arguments args and stores return value in dest.

func (*Env) DeleteGlobalRef

func (j *Env) DeleteGlobalRef(o *ObjectRef)

DeleteGlobalRef deletes global object reference o.

func (*Env) DeleteGlobalRefCache

func (j *Env) DeleteGlobalRefCache()

DeleteGlobalRefCache deletes all globalRef that are in classCache. This methods should be called when an instance of *Env gets out of scope

func (*Env) DeleteLocalRef

func (j *Env) DeleteLocalRef(o *ObjectRef)

DeleteLocalRef deletes object reference o in Env j.

func (*Env) EnsureLocalCapacity

func (j *Env) EnsureLocalCapacity(capacity int32) error

EnsureLocalCapacity calls JNI EnsureLocalCapacity on Env j

func (*Env) FindClass

func (j *Env) FindClass(className string) (*ObjectRef, error)

FindCLass returns reference to java/lang/Class Argument is className of target class

func (*Env) FromObjectArray

func (j *Env) FromObjectArray(objRef *ObjectRef) []*ObjectRef

FromObjectArray converts an Java array of objects objRef in to a slice of *ObjectRef which is returned.

func (*Env) GetClassLoader

func (r *Env) GetClassLoader(obj *ObjectRef) *ClassLoaderRef

Get a class loader object from an existing object obj

func (*Env) GetJVM

func (j *Env) GetJVM() (*JVM, error)

GetJVM Calls JNI GetJavaVM. Needs to be called on an attached thread.

func (*Env) GetStaticField

func (j *Env) GetStaticField(className string, fieldName string, dest interface{}) error

GetField gets field fieldName in class className, stores value in dest.

func (*Env) GetUTF8String

func (j *Env) GetUTF8String() *ObjectRef

GetUTF8String return global reference to java/lang/String containing "UTF-8"

func (*Env) NewByteArray

func (j *Env) NewByteArray(n int) *ByteArray

NewByteArray calls JNI NewByteArray

func (*Env) NewByteArrayFromObject

func (j *Env) NewByteArrayFromObject(o *ObjectRef) *ByteArray

NewByteArrayFromObject creates new ByteArray and sets it from ObjectRef o.

func (*Env) NewByteArrayFromSlice

func (j *Env) NewByteArrayFromSlice(src []byte) *ByteArray

NewByteArrayFromSlice calls JNI NewByteArray and GetCritical, copies src to byte array, calls JNI Release Critical. Returns new byte array.

func (*Env) NewGlobalRef

func (j *Env) NewGlobalRef(o *ObjectRef) *ObjectRef

NewGlobalRef creates a new object reference to o in Env j.

func (*Env) NewObject

func (j *Env) NewObject(className string, args ...interface{}) (*ObjectRef, error)

NewObject calls JNI NewObjectA, className class name of new object, args arguments to constructor.

func (*Env) PopLocalFrame

func (j *Env) PopLocalFrame(result *ObjectRef) *ObjectRef

PopLocalFrame calls JNI popLocalFrame on Env j

func (*Env) PrecalculateSignature

func (j *Env) PrecalculateSignature(sig string)

PrecalculateSignature sets the signature of the next call to sig, disables automatic signature building.

func (*Env) PushLocalFrame

func (j *Env) PushLocalFrame(capacity int32) error

PushLocalFrame calls JNI PushLocalFrame on Env j

func (*Env) RegisterNative

func (j *Env) RegisterNative(className, methodName string, returnType TypeSpec, params []interface{}, fptr interface{}) error

RegisterNative calls JNI RegisterNative for class className, method methodName with return type returnType and parameters params, fptr is used as native function.

func (*Env) SetClassLoader

func (r *Env) SetClassLoader(classLoader *ClassLoaderRef)

Set the env to look up classes using classloader, (it still fall back to JNI findClass function)

func (*Env) SetStaticField

func (j *Env) SetStaticField(className string, fieldName string, value interface{}) error

SetField sets field fieldName in class className to value.

func (*Env) ToGoArray

func (j *Env) ToGoArray(array jobject, aType Type) (interface{}, error)

ToGoArray converts Java prim array object in array with type aType to returned go array. Normally this method does not need to be called because New/Call/Field methods all call this internally.

func (*Env) ToJavaArray

func (j *Env) ToJavaArray(src interface{}) (jobject, error)

ToJavaArray converts go array in src to returned Java prim array object. Normally this method does not need to be called because New/Call/Field methods all call this internally.

func (*Env) ToObjectArray

func (j *Env) ToObjectArray(objRefs []*ObjectRef, className string) (arrayRef *ObjectRef)

ToObjectArray converts slice of ObjectRef objRefs of class name className, to a new Java object array returning a reference to this array.

type ExceptionHandler

type ExceptionHandler interface {
	CatchException(env *Env, exception *ObjectRef) error
}

ExceptionHandler is used to convert a thrown exception (java.lang.Throwable) to a Go error.

var (

	// DefaultExceptionHandler is an alias for DescribeExceptionHandler, which is the default.
	DefaultExceptionHandler = DescribeExceptionHandler

	// DescribeExceptionHandler calls the JNI exceptionDescribe function.
	DescribeExceptionHandler ExceptionHandler = ExceptionHandlerFunc(func(env *Env, exception *ObjectRef) error {
		exceptionDescribe(env.jniEnv)
		exceptionClear(env.jniEnv)
		return errors.New("Java exception occurred. check stderr/logcat")
	})

	// ThrowableToStringExceptionHandler calls ToString on the exception and returns an error
	// with the returned value as its Error message.
	// If exception is nil or the toString() call fails, a generic default error is returned.
	ThrowableToStringExceptionHandler ExceptionHandler = ExceptionHandlerFunc(func(env *Env, exception *ObjectRef) error {
		exceptionClear(env.jniEnv)
		if exception.IsNil() {
			return errThrowableConvertFail
		}
		msg := "Java exception occurred"
		callStringMethodAndAssign(env, exception, "toString", func(s string) {
			if s == "" {
				return
			}
			msg = s
		})
		return errors.New(msg)
	})

	// ThrowableErrorExceptionHandler populates a new ThrowableError with the values of exception.
	// If exception is nil, the getClass().getName(), or the toString call fails, a generic default
	// error is returned.
	ThrowableErrorExceptionHandler ExceptionHandler = ExceptionHandlerFunc(func(env *Env, exception *ObjectRef) error {
		exceptionClear(env.jniEnv)
		if exception.IsNil() {
			return errThrowableConvertFail
		}
		throwableError, _ := NewThrowableErrorFromObject(env, exception)
		if throwableError == nil {
			return errThrowableConvertFail
		}
		return *throwableError
	})
)

type ExceptionHandlerFunc

type ExceptionHandlerFunc func(env *Env, exception *ObjectRef) error

ExceptionHandlerFunc is an adapter to allow use of ordinary functions as an ExceptionHandler. If f is a function with the appropriate signature, ExceptionHandlerFunc(f) is an ExceptionHandler object that calls f.

func (ExceptionHandlerFunc) CatchException

func (f ExceptionHandlerFunc) CatchException(env *Env, exception *ObjectRef) error

CatchException calls f to implement ExceptionHandler.

type JVM

type JVM struct {
	// contains filtered or unexported fields
}

JVM holds a JavaVM value, you only need one of these in your app.

func (*JVM) AttachCurrentThread

func (j *JVM) AttachCurrentThread() *Env

AttachCurrentThread calls JNI AttachCurrentThread. Must call runtime.LockOSThread() first.

func (*JVM) Destroy

func (j *JVM) Destroy() error

Destroy calls JNI DestroyJavaVM

func (*JVM) DetachCurrentThread

func (j *JVM) DetachCurrentThread(env *Env) error

DetachCurrentThread calls JNI DetachCurrentThread, pass Env returned from AttachCurrentThread for current thread.

type JVMInitArgs

type JVMInitArgs struct {
	// contains filtered or unexported fields
}

JVMInitArgs holds a JavaVMInitArgs value

func NewJVMInitArgs

func NewJVMInitArgs(ignoreUnrecognizedArgs bool, includeDefaultArgs bool, version int, args []string) *JVMInitArgs

NewJVMInitArgs builds JNI JavaVMInitArgs using GetDefaultJavaVMInitArgs and parameters.

type ObjectArrayType

type ObjectArrayType string

ObjectArrayType is treated as Object | Array Type. It's value specify the class of the elements. Implements TypeSpec.

type ObjectRef

type ObjectRef struct {
	// contains filtered or unexported fields
}

ObjectRef holds a reference to a Java Object

func NewObjectArrayRef

func NewObjectArrayRef(className string) *ObjectRef

NewObjectArrayRef returns new *ObjectRef with Nil JNI object array reference and class name set to className.

func NewObjectRef

func NewObjectRef(className string) *ObjectRef

NewObjectRef returns new *ObjectRef with Nil JNI object reference and class name set to className.

func WrapJObject

func WrapJObject(jobj uintptr, className string, isArray bool) *ObjectRef

WrapJObject wraps a JNI object value in an ObjectRef

func (*ObjectRef) CallMethod

func (o *ObjectRef) CallMethod(env *Env, methodName string, dest interface{}, args ...interface{}) error

CallMethod calls method methodName on o with arguments args and stores return value in dest.

func (*ObjectRef) CallNonvirtualMethod

func (o *ObjectRef) CallNonvirtualMethod(env *Env, className string, methodName string, dest interface{}, args ...interface{}) error

CallNonvirtualMethod calls non virtual method methodName on o with arguments args and stores return value in dest.

func (*ObjectRef) Cast

func (o *ObjectRef) Cast(className string) *ObjectRef

Cast return a new *ObjectRef containing the receiver jobject and with class name set to className.

func (*ObjectRef) GetClassName

func (o *ObjectRef) GetClassName() string

GetClassName returns class name of object reference.

func (*ObjectRef) GetField

func (o *ObjectRef) GetField(env *Env, fieldName string, dest interface{}) error

GetField gets field fieldName in o and stores value in dest.

func (*ObjectRef) IsArray

func (o *ObjectRef) IsArray() bool

IsArray returns true if reference is to object array.

func (*ObjectRef) IsInstanceOf

func (o *ObjectRef) IsInstanceOf(env *Env, className string) (bool, error)

IsInstanceOf returns true if o is an instance of className

func (*ObjectRef) IsNil

func (o *ObjectRef) IsNil() bool

IsNil is true if ObjectRef has a Nil Java value

func (*ObjectRef) JObject

func (o *ObjectRef) JObject() jobject

JObject gets JNI object value of o

func (*ObjectRef) SetField

func (o *ObjectRef) SetField(env *Env, fieldName string, value interface{}) error

SetField sets field fieldName in o to value.

type ObjectType

type ObjectType string

ObjectType is treated as Object Type. It's value is used to specify the class of the object. For example jnigi.ObjectType("java/lang/string"). Implements TypeSpec.

type StackTraceElement

type StackTraceElement struct {
	ClassName      string
	FileName       string
	LineNumber     int
	MethodName     string
	IsNativeMethod bool
	AsString       string
}

StackTraceElement is a struct holding the contents of java.lang.StackTraceElement for use in a ThrowableError.

func NewStackTraceElementFromObject

func NewStackTraceElementFromObject(env *Env, stackTraceElement *ObjectRef) (*StackTraceElement, error)

NewStackTraceElementFromObject creates a new StackTraceElement with its contents set from the values provided in stackTraceElement's methods.

func (StackTraceElement) String

func (el StackTraceElement) String() string

type ThrowableError

type ThrowableError struct {
	ClassName        string
	LocalizedMessage string
	Message          string
	StackTrace       []StackTraceElement
	AsString         string
	Cause            *ThrowableError
}

ThrowableError is an error struct that holds the relevant contents of a java.lang.Throwable. This is the returned error from ThrowableErrorExceptionHandler.

func NewThrowableErrorFromObject

func NewThrowableErrorFromObject(env *Env, throwable *ObjectRef) (*ThrowableError, error)

NewThrowableErrorFromObject creates a new ThrowableError with its contents set from the values provided in throwable's methods.

func (ThrowableError) Error

func (e ThrowableError) Error() string

func (ThrowableError) String

func (e ThrowableError) String() string

type ToGoConverter

type ToGoConverter interface {
	// Method should delete reference if it is not needed anymore
	ConvertToGo(obj *ObjectRef) error
}

Types that can covert to Go values from object reference

type ToJavaConverter

type ToJavaConverter interface {
	// Returned reference will be deleted
	ConvertToJava() (*ObjectRef, error)
}

Types that can convert to Java Object

type Type

type Type uint32

Type is used to specify return types and field types. Array value can be ORed with primitive type. Implements TypeSpec. See package constants for values.

type TypeGetter

type TypeGetter interface {
	GetType() Type
}

TypeGetter can be implemented to control which primitive type a value is treated as.

type TypeSpec

type TypeSpec interface {
	// contains filtered or unexported methods
}

TypeSpec is implemented by Type, ObjectType and ObjectArrayType.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL