diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9245165 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.go-old diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5517188 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.wow.st/gmp/jni + +go 1.14 diff --git a/gojni.h b/gojni.h index 66dbf6b..b4c0e78 100644 --- a/gojni.h +++ b/gojni.h @@ -1,3 +1,7 @@ +#ifndef __ANDROID_API__ +__attribute__ ((visibility ("hidden"))) JavaVM *_jni_CreateJavaVM(const char **options, int nOptions); +#endif /* __ANDROID_API__ */ + __attribute__ ((visibility ("hidden"))) jint _jni_GetEnv(JavaVM *vm, JNIEnv **env, jint version); __attribute__ ((visibility ("hidden"))) jint _jni_AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args); __attribute__ ((visibility ("hidden"))) jint _jni_DetachCurrentThread(JavaVM *vm); @@ -7,15 +11,20 @@ __attribute__ ((visibility ("hidden"))) void _jni_ExceptionClear(JNIEnv *env); __attribute__ ((visibility ("hidden"))) jclass _jni_GetObjectClass(JNIEnv *env, jobject obj); __attribute__ ((visibility ("hidden"))) jmethodID _jni_GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); __attribute__ ((visibility ("hidden"))) jmethodID _jni_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); +__attribute__ ((visibility ("hidden"))) jfieldID _jni_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); __attribute__ ((visibility ("hidden"))) jfieldID _jni_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); __attribute__ ((visibility ("hidden"))) jsize _jni_GetStringLength(JNIEnv *env, jstring str); __attribute__ ((visibility ("hidden"))) const jchar *_jni_GetStringChars(JNIEnv *env, jstring str); __attribute__ ((visibility ("hidden"))) jstring _jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len); __attribute__ ((visibility ("hidden"))) jboolean _jni_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); +__attribute__ ((visibility ("hidden"))) jboolean _jni_IsInstanceOf(JNIEnv *env, jobject obj, jclass cls); __attribute__ ((visibility ("hidden"))) jobject _jni_NewGlobalRef(JNIEnv *env, jobject obj); __attribute__ ((visibility ("hidden"))) void _jni_DeleteGlobalRef(JNIEnv *env, jobject obj); +__attribute__ ((visibility ("hidden"))) jobject _jni_NewLocalRef(JNIEnv *env, jobject obj); +__attribute__ ((visibility ("hidden"))) void _jni_DeleteLocalRef(JNIEnv *env, jobject obj); __attribute__ ((visibility ("hidden"))) jint _jni_CallStaticIntMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) jobject _jni_CallStaticObjectMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); +__attribute__ ((visibility ("hidden"))) jobject _jni_NewObjectA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) void _jni_CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) jobject _jni_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) jint _jni_CallIntMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); @@ -33,3 +42,12 @@ __attribute__ ((visibility ("hidden"))) jint _jni_GetStaticIntField(JNIEnv *env, __attribute__ ((visibility ("hidden"))) jlong _jni_GetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID); __attribute__ ((visibility ("hidden"))) jfloat _jni_GetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID); __attribute__ ((visibility ("hidden"))) jdouble _jni_GetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jobject _jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jboolean _jni_GetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jbyte _jni_GetByteField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jchar _jni_GetCharField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jshort _jni_GetShortField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jint _jni_GetIntField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jlong _jni_GetLongField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jfloat _jni_GetFloatField(JNIEnv *env, jobject obj, jfieldID fieldID); +__attribute__ ((visibility ("hidden"))) jdouble _jni_GetDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID); diff --git a/jni.c b/jni.c index 84c743a..dea749d 100644 --- a/jni.c +++ b/jni.c @@ -1,5 +1,31 @@ +#include #include +#ifndef __ANDROID_API__ +JavaVM *_jni_CreateJavaVM(char **optstrings, int nOptions) { + JavaVM *vm; + JNIEnv *p_env; + JavaVMInitArgs vm_args; + JavaVMOption *options = (JavaVMOption *)malloc(sizeof(JavaVMOption)*nOptions); + if (options != 0) { + int i; + for (i = 0; i < nOptions; i++) { + options[i].optionString = optstrings[i]; + } + vm_args.nOptions = nOptions; + vm_args.options = options; + } + vm_args.version = JNI_VERSION_1_6; + vm_args.ignoreUnrecognized = 0; + jint res = JNI_CreateJavaVM(&vm, &p_env, &vm_args); + if (res < 0) { + printf("Can't create Java VM\n"); + return 0; + } + return vm; +} +#endif /* __ANDROID_API__ */ + jint _jni_AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args) { return (*vm)->AttachCurrentThread(vm, p_env, thr_args); } @@ -36,6 +62,10 @@ jmethodID _jni_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, co return (*env)->GetStaticMethodID(env, clazz, name, sig); } +jfieldID _jni_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { + return (*env)->GetFieldID(env, clazz, name, sig); +} + jfieldID _jni_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) { return (*env)->GetStaticFieldID(env, clazz, name, sig); } @@ -56,6 +86,10 @@ jboolean _jni_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2) { return (*env)->IsSameObject(env, ref1, ref2); } +jboolean _jni_IsInstanceOf(JNIEnv *env, jobject obj, jclass cls) { + return (*env)->IsInstanceOf(env, obj, cls); +} + jobject _jni_NewGlobalRef(JNIEnv *env, jobject obj) { return (*env)->NewGlobalRef(env, obj); } @@ -64,6 +98,18 @@ void _jni_DeleteGlobalRef(JNIEnv *env, jobject obj) { (*env)->DeleteGlobalRef(env, obj); } +jobject _jni_NewLocalRef(JNIEnv *env, jobject obj) { + return (*env)->NewLocalRef(env, obj); +} + +void _jni_DeleteLocalRef(JNIEnv *env, jobject obj) { + (*env)->DeleteLocalRef(env, obj); +} + +jobject _jni_NewObjectA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args) { + return (*env)->NewObject(env, cls, method, args); +} + void _jni_CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID method, jvalue *args) { (*env)->CallStaticVoidMethodA(env, cls, method, args); } @@ -140,3 +186,39 @@ jdouble _jni_GetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID) { return (*env)->GetStaticDoubleField(env, clazz, fieldID); } +jobject _jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetObjectField(env, obj, fieldID); +} + +jboolean _jni_GetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetBooleanField(env, obj, fieldID); +} + +jbyte _jni_GetByteField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetByteField(env, obj, fieldID); +} + +jchar _jni_GetCharField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetCharField(env, obj, fieldID); +} + +jshort _jni_GetShortField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetShortField(env, obj, fieldID); +} + +jint _jni_GetIntField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetIntField(env, obj, fieldID); +} + +jlong _jni_GetLongField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetLongField(env, obj, fieldID); +} + +jfloat _jni_GetFloatField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetFloatField(env, obj, fieldID); +} + +jdouble _jni_GetDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID) { + return (*env)->GetDoubleField(env, obj, fieldID); +} + diff --git a/jni.go b/jni.go index 8cc7eee..49cf026 100644 --- a/jni.go +++ b/jni.go @@ -4,8 +4,17 @@ package jni -// Package jni implements various helper functions for communicating with the Android JVM -// though JNI. +// Package jni implements various helper functions for communicating with the +// Android JVM though JNI. + +/* +#cgo CFLAGS: -Wall + +#include +#include +#include "gojni.h" +*/ +import "C" import ( "errors" @@ -16,16 +25,6 @@ import ( "unsafe" ) -/* -#cgo CFLAGS: -Wall - -#include -#include - -#include "gojni.h" -*/ -import "C" - type JVM struct { jvm *C.JavaVM } @@ -92,6 +91,25 @@ func CallStaticIntMethod(e Env, cls Class, method MethodID, args ...Value) (int, return int(res), exception(e) } +// FindClass finds a class with a given name, using the JVM's default +// class loader. +func FindClass(e Env, name string) Class { + mname := C.CString(name) + defer C.free(unsafe.Pointer(mname)) + res := C._jni_FindClass(e.env, mname) + if err := exception(e); err != nil { + panic(err) + } + return Class(res) +} + +// NewObject creates a new object given a class, initializer methodID, and +// arguments (if any). +func NewObject(e Env, cls Class, method MethodID, args ...Value) (Object, error) { + res := C._jni_NewObjectA(e.env, C.jclass(cls), C.jmethodID(method), varArgs(args)) + return Object(res), exception(e) +} + func CallStaticVoidMethod(e Env, cls Class, method MethodID, args ...Value) error { C._jni_CallStaticVoidMethodA(e.env, C.jclass(cls), C.jmethodID(method), varArgs(args)) return exception(e) @@ -199,6 +217,22 @@ func GetObjectClass(e Env, obj Object) Class { return Class(cls) } +// IsInstanceOf returns true if the given object is an instance of the +// given class. +func IsInstanceOf(e Env, obj Object, cls Class) bool { + if obj == 0 { + panic("null object") + } + if cls == 0 { + panic("null class") + } + res := C._jni_IsInstanceOf(e.env, C.jobject(obj), C.jclass(cls)) + if err := exception(e); err != nil { + panic(err) + } + return res == C.JNI_TRUE +} + // GetStaticMethodID returns the id for a static method. It panics if the method // wasn't found. func GetStaticMethodID(e Env, cls Class, name, signature string) MethodID { @@ -213,6 +247,19 @@ func GetStaticMethodID(e Env, cls Class, name, signature string) MethodID { return MethodID(m) } +// GetFieldID returns the id for a field. It panics if the field wasn't found. +func GetFieldID(e Env, cls Class, name, signature string) FieldID { + mname := C.CString(name) + defer C.free(unsafe.Pointer(mname)) + msig := C.CString(signature) + defer C.free(unsafe.Pointer(msig)) + m := C._jni_GetFieldID(e.env, C.jclass(cls), mname, msig) + if err := exception(e); err != nil { + panic(err) + } + return FieldID(m) +} + // GetStaticFieldID returns the id for a static field. It panics if the field // wasn't found. func GetStaticFieldID(e Env, cls Class, name, signature string) FieldID { @@ -241,14 +288,26 @@ func GetMethodID(e Env, cls Class, name, signature string) MethodID { return MethodID(m) } +// NewGlobalRef creates a new global reference. func NewGlobalRef(e Env, obj Object) Object { return Object(C._jni_NewGlobalRef(e.env, C.jobject(obj))) } +// DeleteGlobalRef delets a global reference. func DeleteGlobalRef(e Env, obj Object) { C._jni_DeleteGlobalRef(e.env, C.jobject(obj)) } +// NewLocalRef creates a new local reference to the given object. +func NewLocalRef(e Env, obj Object) Object { + return Object(C._jni_NewLocalRef(e.env, C.jobject(obj))) +} + +// DeleteLocalRef delets a local reference. +func DeleteLocalRef(e Env, obj Object) { + C._jni_DeleteLocalRef(e.env, C.jobject(obj)) +} + // JavaString converts the string to a JVM jstring. func JavaString(e Env, str string) String { if str == "" { @@ -364,3 +423,93 @@ func GetStaticDoubleField(env Env, clazz Class, fieldID FieldID) float64 { } return float64(value) } + +// GetObjectField looks up the value of a static field of type Object. +// It panics if it is unable to find the field. +func GetObjectField(env Env, obj Object, fieldID FieldID) Object { + value := C._jni_GetObjectField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return Object(value) +} + +// GetBooleanField looks up the value of a static field of type boolean. +// It panics if it is unable to find the field. +func GetBooleanField(env Env, obj Object, fieldID FieldID) bool { + value := C._jni_GetBooleanField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return value != 0 +} + +// GetByteField looks up the value of a static field of type byte. +// It panics if it is unable to find the field. +func GetByteField(env Env, obj Object, fieldID FieldID) byte { + value := C._jni_GetByteField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return byte(value) +} + +// GetCharField looks up the value of a static field of type char. +// It panics if it is unable to find the field. +func GetCharField(env Env, obj Object, fieldID FieldID) byte { + value := C._jni_GetCharField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return byte(value) +} + +// GetShortField looks up the value of a static field of type short. +// It panics if it is unable to find the field. +func GetShortField(env Env, obj Object, fieldID FieldID) int16 { + value := C._jni_GetShortField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return int16(value) +} + +// GetIntField looks up the value of a static field of type int. +// It panics if it is unable to find the field. +func GetIntField(env Env, obj Object, fieldID FieldID) int32 { + value := C._jni_GetIntField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return int32(value) +} + +// GetLongField looks up the value of a static field of type long. +// It panics if it is unable to find the field. +func GetLongField(env Env, obj Object, fieldID FieldID) int64 { + value := C._jni_GetLongField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return int64(value) +} + +// GetFloatField looks up the value of a static field of type float. +// It panics if it is unable to find the field. +func GetFloatField(env Env, obj Object, fieldID FieldID) float32 { + value := C._jni_GetFloatField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return float32(value) +} + +// GetDoubleField looks up the value of a static field of type double. +// It panics if it is unable to find the field. +func GetDoubleField(env Env, obj Object, fieldID FieldID) float64 { + value := C._jni_GetDoubleField(env.env, C.jobject(obj), C.jfieldID(fieldID)) + if err := exception(env); err != nil { + panic(err) + } + return float64(value) +} diff --git a/jni_darwin.go b/jni_darwin.go new file mode 100644 index 0000000..b6f75ca --- /dev/null +++ b/jni_darwin.go @@ -0,0 +1,11 @@ +// +build darwin +//go:generate ./find_jnih jni_darwin.go2 +//Generated by scripts/find_macos_jnih + +package jni + +/* +#cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/include/darwin +#cgo LDFLAGS: -ljvm +*/ +import "C" diff --git a/jni_notandroid.go b/jni_notandroid.go new file mode 100644 index 0000000..508a77a --- /dev/null +++ b/jni_notandroid.go @@ -0,0 +1,37 @@ +// +build !android + +package jni + +/* +#include +#include +#include "gojni.h" +*/ +import "C" + +import ( + "unsafe" +) + +// CreateJavaVM creates a new Java VM with the options specified (if any). +// This should not be called more than once as it can result in an error if +// a JVM already exists for a given process. +// +// This is not implemented on Android and is therefore excluded on that +// platform by build flags and C. +func CreateJavaVM(opts ...string) JVM { + nOptions := len(opts) + optstrings := make([]*C.char, nOptions) + for i, _ := range optstrings { + optstrings[i] = C.CString(opts[i]) + defer C.free(unsafe.Pointer(optstrings[i])) + } + var jvm *C.JavaVM + if nOptions > 0 { + jvm = C._jni_CreateJavaVM(&optstrings[0], C.int(nOptions)) + } else { + jvm = C._jni_CreateJavaVM((**C.char)(nil), 0) + } + return JVM{ jvm: jvm } +} + diff --git a/jni_test.go b/jni_test.go new file mode 100644 index 0000000..ca960f1 --- /dev/null +++ b/jni_test.go @@ -0,0 +1,318 @@ +// +build darwin +//go:generate javac test/AClass.java + +package jni + +import ( + "sync" + "testing" +) + +var ( + vm JVM + vmOnce sync.Once +) + +func TestCreateJVM(t *testing.T) { + // Do not try to create more than one JVM + vmOnce.Do(func() { + res := CreateJavaVM() + if res.jvm == nil { + t.Errorf("CreateJavaVM() returned nil") + } else { + vm = res + } + }) +} + +func TestFindClass(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + if cls == 0 { + t.Errorf("Class is nil") + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestGetMethodID(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + if mid == nil { + t.Errorf("MethodID is nil") + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestNewObject(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + if err != nil { + t.Errorf("NewObject raised exception") + } + if inst == 0 { + t.Errorf("NewObject returned nil") + } + inst = NewGlobalRef(env, inst) + if inst == 0 { + t.Errorf("NewGlobalRef returned nil") + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestIsSameObject(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + if !IsSameObject(env, inst, inst) { + t.Errorf("Object is not the same as itself") + } + inst2, err := NewObject(env, cls, mid) + if err != nil { + t.Errorf("Object is nil") + } + if IsSameObject(env, inst, inst2) { + t.Errorf("Different objects are the same") + } + inst2 = NewLocalRef(env, inst) + if !IsSameObject(env, inst, inst2) { + t.Errorf("New local ref is not the same as original object") + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestStaticIntMethod(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + mid = GetStaticMethodID(env, cls, "GetStaticInt", "()I") + if mid == nil { + t.Errorf("MethodID is nil") + } + res, err := CallStaticIntMethod(env, cls, mid) + if err != nil { + t.Errorf("Method invocation failed") + } + if res != 100 { + t.Errorf("Method returned %d, not expected value of %d.", res, 100) + } + return err + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestIntMethod(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + mid = GetMethodID(env, cls, "GetInt", "()I") + if mid == nil { + t.Errorf("MethodID is nil") + } + res, err := CallIntMethod(env, inst, mid) + if err != nil { + t.Errorf("Method invocation failed") + } + if res != 0 { + t.Errorf("Method returned %d, not expected value of %d.", res, 0) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestVoidMethod(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + mid = GetMethodID(env, cls, "IncInt", "()V") + if mid == nil { + t.Errorf("MethodID is nil") + } + err = CallVoidMethod(env, inst, mid) + if err != nil { + t.Errorf("Method invocation failed") + } + mid = GetMethodID(env, cls, "GetInt", "()I") + res, err := CallIntMethod(env, inst, mid) + if err != nil { + t.Errorf("Method invocation falied") + } + if res != 1 { + t.Errorf("Method returned %d, not expected value of %d.", res, 1) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestVoidMethod2(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + mid = GetMethodID(env, cls, "SetInt", "(I)V") + if mid == nil { + t.Errorf("MethodID is nil") + } + err = CallVoidMethod(env, inst, mid, 5) + if err != nil { + t.Errorf("Method invocation failed") + } + mid = GetMethodID(env, cls, "GetInt", "()I") + res, err := CallIntMethod(env, inst, mid) + if err != nil { + t.Errorf("Method invocation falied") + } + if res != 5 { + t.Errorf("Method returned %d, not expected value of %d.", res, 5) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestVoidMethod3(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, err := NewObject(env, cls, mid) + mid = GetMethodID(env, cls, "AddInts", "(II)V") + if mid == nil { + t.Errorf("MethodID is nil") + } + err = CallVoidMethod(env, inst, mid, 9, 11) + if err != nil { + t.Errorf("Method invocation failed") + } + mid = GetMethodID(env, cls, "GetInt", "()I") + res, err := CallIntMethod(env, inst, mid) + if err != nil { + t.Errorf("Method invocation falied") + } + if res != 20 { + t.Errorf("Method returned %d, not expected value of %d.", res, 20) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestStaticVoidMethod(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetStaticMethodID(env, cls, "SetStaticInt", "(I)V") + if mid == nil { + t.Errorf("MethodID is nil") + } + err := CallStaticVoidMethod(env, cls, mid, 200) + if err != nil { + t.Errorf("Method invocation failed: %s", err) + } + mid = GetStaticMethodID(env, cls, "GetStaticInt", "()I") + res, err := CallStaticIntMethod(env, cls, mid) + if err != nil { + t.Errorf("Method invocation falied: %s", err) + } + if res != 200 { + t.Errorf("Method returned %d, not expected value of %d.", res, 200) + } + mid = GetStaticMethodID(env, cls, "SetStaticInt", "(I)V") + err = CallStaticVoidMethod(env, cls, mid, 100) + if err != nil { + t.Errorf("Method invocation failed: %s", err) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestGetObjectClass(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, _ := NewObject(env, cls, mid) + cls2 := GetObjectClass(env, inst) + if cls2 == 0 { + t.Errorf("GetObjectClass returned nil") + } + if !IsInstanceOf(env, inst, cls2) { + t.Errorf("IsInstanceOf failed") + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestField(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + mid := GetMethodID(env, cls, "", "()V") + inst, _ := NewObject(env, cls, mid) + fid := GetFieldID(env, cls, "intval", "I") + if fid == nil { + t.Errorf("FieldID is nil") + } + res := GetIntField(env, inst, fid) + if res != 0 { + t.Errorf("Method returned %d, not expected value of %d.", res, 0) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestStaticField(t *testing.T) { + err := Do(vm, func(env Env) error { + cls := FindClass(env, "test/AClass") + fid := GetStaticFieldID(env, cls, "staticintval", "I") + if fid == nil { + t.Errorf("FieldID is nil") + } + res := GetStaticIntField(env, cls, fid) + if res != 100 { + t.Errorf("Method returned %d, not expected value of %d.", res, 100) + } + return nil + }) + if err != nil { + t.Errorf("Error: %s", err) + } +} diff --git a/scripts/find_macos_jnih b/scripts/find_macos_jnih new file mode 100755 index 0000000..a2a0a83 --- /dev/null +++ b/scripts/find_macos_jnih @@ -0,0 +1,18 @@ +#!/bin/bash + +JAVA_HOME=`/usr/libexec/java_home` + +echo // +build darwin > jni_darwin.tmp +echo //go:generate ./find_jnih jni_darwin.go2 >> jni_darwin.tmp +echo //Generated by scripts/find_macos_jnih >> jni_darwin.tmp +echo >> jni_darwin.tmp +echo package jni >> jni_darwin.tmp +echo >> jni_darwin.tmp +echo /\* >> jni_darwin.tmp +echo \#cgo CFLAGS: -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin >> jni_darwin.tmp +echo \#cgo LDFLAGS: -ljvm >> jni_darwin.tmp +echo \*/ >> jni_darwin.tmp +echo import \"C\" >> jni_darwin.tmp + +mv -f jni_darwin.go jni_darwin.go-old +mv jni_darwin.tmp jni_darwin.go diff --git a/test/AClass.class b/test/AClass.class new file mode 100644 index 0000000..b7a71a5 Binary files /dev/null and b/test/AClass.class differ diff --git a/test/AClass.java b/test/AClass.java new file mode 100644 index 0000000..4ea82d6 --- /dev/null +++ b/test/AClass.java @@ -0,0 +1,31 @@ +package test; + +public class AClass { + public static int staticintval = 100; + + public int intval = 0; + + public static int GetStaticInt() { + return staticintval; + } + + public static void SetStaticInt(int val) { + staticintval = val; + } + + public void IncInt() { + intval = intval + 1; + } + + public int GetInt() { + return intval; + } + + public void SetInt(int val) { + intval = val; + } + + public void AddInts(int val1, int val2) { + intval = val1 + val2; + } +}