1
0
forked from gmp/jni

Compare commits

..

8 Commits

Author SHA1 Message Date
ff2a63c99a
feat: implement calling static boolean methods
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2021-04-18 14:41:05 -04:00
gmp
014cd5c7c4 Merge branch 'master' of jeffwilliams/jni into master 2020-08-27 15:41:56 +00:00
396d6d4dec Fix bug in last commit 2020-08-07 08:21:05 -04:00
3310c43bcf Make find_linux_jnih more robust. 2020-08-07 08:05:48 -04:00
15a239885b Add support for object arrays. 2020-08-05 22:24:04 -04:00
4a3b173acb Merge remote-tracking branch 'origin/master' into HEAD 2020-07-09 17:08:36 -04:00
2cf43e041c Improve test coverage. 2020-07-09 17:07:34 -04:00
gmp
b33150047f Merge branch 'master' of whereswaldon/jni into master 2020-06-26 21:27:01 +00:00
10 changed files with 692 additions and 144 deletions

View File

@ -38,6 +38,9 @@ __attribute__ ((visibility ("hidden"))) jlong _jni_CallLongMethodA(JNIEnv *env,
__attribute__ ((visibility ("hidden"))) jfloat _jni_CallFloatMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) jfloat _jni_CallFloatMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args);
__attribute__ ((visibility ("hidden"))) jdouble _jni_CallDoubleMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args); __attribute__ ((visibility ("hidden"))) jdouble _jni_CallDoubleMethodA(JNIEnv *env, jobject obj, jmethodID method, jvalue *args);
__attribute__ ((visibility ("hidden"))) jbyteArray _jni_NewByteArray(JNIEnv *env, jsize length); __attribute__ ((visibility ("hidden"))) jbyteArray _jni_NewByteArray(JNIEnv *env, jsize length);
__attribute__ ((visibility ("hidden"))) jobjectArray _jni_NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
__attribute__ ((visibility ("hidden"))) jobject _jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
__attribute__ ((visibility ("hidden"))) void _jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
__attribute__ ((visibility ("hidden"))) jbyte *_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr); __attribute__ ((visibility ("hidden"))) jbyte *_jni_GetByteArrayElements(JNIEnv *env, jbyteArray arr);
__attribute__ ((visibility ("hidden"))) void _jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *elems, jint mode); __attribute__ ((visibility ("hidden"))) void _jni_ReleaseByteArrayElements(JNIEnv *env, jbyteArray arr, jbyte *elems, jint mode);
__attribute__ ((visibility ("hidden"))) jsize _jni_GetArrayLength(JNIEnv *env, jarray arr); __attribute__ ((visibility ("hidden"))) jsize _jni_GetArrayLength(JNIEnv *env, jarray arr);

12
jni.c
View File

@ -182,6 +182,18 @@ jsize _jni_GetArrayLength(JNIEnv *env, jarray arr) {
return (*env)->GetArrayLength(env, arr); return (*env)->GetArrayLength(env, arr);
} }
jobjectArray _jni_NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement) {
return (*env)->NewObjectArray(env, length, elementClass, initialElement);
}
jobject _jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index) {
return (*env)->GetObjectArrayElement(env, array, index);
}
void _jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value) {
return (*env)->SetObjectArrayElement(env, array, index, value);
}
jobject _jni_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID) { jobject _jni_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID) {
return (*env)->GetStaticObjectField(env, clazz, fieldID); return (*env)->GetStaticObjectField(env, clazz, fieldID);
} }

141
jni.go
View File

@ -33,13 +33,15 @@ type Env struct {
} }
type ( type (
Class C.jclass Class C.jclass
Object C.jobject Object C.jobject
MethodID C.jmethodID MethodID C.jmethodID
FieldID C.jfieldID FieldID C.jfieldID
String C.jstring String C.jstring
ByteArray C.jbyteArray ByteArray C.jbyteArray
Value uint64 // All JNI types fit into 64-bits. ObjectArray C.jobjectArray
Size C.jsize
Value uint64 // All JNI types fit into 64-bits.
) )
const ( const (
@ -93,7 +95,7 @@ func varArgs(args []Value) *C.jvalue {
// Java object. // Java object.
func IsSameObject(e Env, ref1, ref2 Object) bool { func IsSameObject(e Env, ref1, ref2 Object) bool {
same := C._jni_IsSameObject(e.env, C.jobject(ref1), C.jobject(ref2)) same := C._jni_IsSameObject(e.env, C.jobject(ref1), C.jobject(ref2))
return same == C.JNI_TRUE return same == TRUE
} }
// CallStaticIntMethod calls a static method on a Java class, returning an int. // CallStaticIntMethod calls a static method on a Java class, returning an int.
@ -227,6 +229,28 @@ func NewByteArray(e Env, content []byte) ByteArray {
return ByteArray(jarr) return ByteArray(jarr)
} }
func NewObjectArray(e Env, len Size, class Class, elem Object) ObjectArray {
jarr := C._jni_NewObjectArray(e.env, C.jsize(len), C.jclass(class), C.jobject(elem))
if jarr == 0 {
panic(fmt.Errorf("jni: NewObjectArray failed"))
}
return ObjectArray(jarr)
}
func GetObjectArrayElement(e Env, jarr ObjectArray, index Size) (Object, error) {
jobj := C._jni_GetObjectArrayElement(e.env, C.jobjectArray(jarr), C.jsize(index))
return Object(jobj), exception(e)
}
func SetObjectArrayElement(e Env, jarr ObjectArray, index Size, value Object) error {
C._jni_SetObjectArrayElement(
e.env,
C.jobjectArray(jarr),
C.jsize(index),
C.jobject(value))
return exception(e)
}
// ClassLoader returns a reference to the Java ClassLoader associated // ClassLoader returns a reference to the Java ClassLoader associated
// with obj. // with obj.
func ClassLoaderFor(e Env, obj Object) Object { func ClassLoaderFor(e Env, obj Object) Object {
@ -276,11 +300,8 @@ func GetObjectClass(e Env, obj Object) Class {
if obj == 0 { if obj == 0 {
panic("null object") panic("null object")
} }
// GetObjectClass does not throw any exceptions
cls := C._jni_GetObjectClass(e.env, C.jobject(obj)) cls := C._jni_GetObjectClass(e.env, C.jobject(obj))
if err := exception(e); err != nil {
// GetObjectClass should never fail.
panic(err)
}
return Class(cls) return Class(cls)
} }
@ -293,11 +314,9 @@ func IsInstanceOf(e Env, obj Object, cls Class) bool {
if cls == 0 { if cls == 0 {
panic("null class") panic("null class")
} }
// Note: does not throw any exceptions
res := C._jni_IsInstanceOf(e.env, C.jobject(obj), C.jclass(cls)) res := C._jni_IsInstanceOf(e.env, C.jobject(obj), C.jclass(cls))
if err := exception(e); err != nil { return res == TRUE
panic(err)
}
return res == C.JNI_TRUE
} }
// GetStaticMethodID returns the id for a static method. It panics if the method // GetStaticMethodID returns the id for a static method. It panics if the method
@ -402,181 +421,127 @@ func GoString(e Env, str String) string {
} }
// GetStaticObjectField looks up the value of a static field of type Object. // GetStaticObjectField looks up the value of a static field of type Object.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticObjectField(env Env, clazz Class, fieldID FieldID) Object { func GetStaticObjectField(env Env, clazz Class, fieldID FieldID) Object {
value := C._jni_GetStaticObjectField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticObjectField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return Object(value) return Object(value)
} }
// GetStaticBooleanField looks up the value of a static field of type boolean. // GetStaticBooleanField looks up the value of a static field of type boolean.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticBooleanField(env Env, clazz Class, fieldID FieldID) bool { func GetStaticBooleanField(env Env, clazz Class, fieldID FieldID) bool {
value := C._jni_GetStaticBooleanField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticBooleanField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return value != 0 return value != 0
} }
// GetStaticByteField looks up the value of a static field of type byte. // GetStaticByteField looks up the value of a static field of type byte.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticByteField(env Env, clazz Class, fieldID FieldID) byte { func GetStaticByteField(env Env, clazz Class, fieldID FieldID) byte {
value := C._jni_GetStaticByteField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticByteField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return byte(value) return byte(value)
} }
// GetStaticCharField looks up the value of a static field of type char. // GetStaticCharField looks up the value of a static field of type char.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticCharField(env Env, clazz Class, fieldID FieldID) byte { func GetStaticCharField(env Env, clazz Class, fieldID FieldID) byte {
value := C._jni_GetStaticCharField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticCharField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return byte(value) return byte(value)
} }
// GetStaticShortField looks up the value of a static field of type short. // GetStaticShortField looks up the value of a static field of type short.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticShortField(env Env, clazz Class, fieldID FieldID) int16 { func GetStaticShortField(env Env, clazz Class, fieldID FieldID) int16 {
value := C._jni_GetStaticShortField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticShortField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int16(value) return int16(value)
} }
// GetStaticIntField looks up the value of a static field of type int. // GetStaticIntField looks up the value of a static field of type int.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticIntField(env Env, clazz Class, fieldID FieldID) int32 { func GetStaticIntField(env Env, clazz Class, fieldID FieldID) int32 {
value := C._jni_GetStaticIntField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticIntField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int32(value) return int32(value)
} }
// GetStaticLongField looks up the value of a static field of type long. // GetStaticLongField looks up the value of a static field of type long.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticLongField(env Env, clazz Class, fieldID FieldID) int64 { func GetStaticLongField(env Env, clazz Class, fieldID FieldID) int64 {
value := C._jni_GetStaticLongField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticLongField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int64(value) return int64(value)
} }
// GetStaticFloatField looks up the value of a static field of type float. // GetStaticFloatField looks up the value of a static field of type float.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticFloatField(env Env, clazz Class, fieldID FieldID) float32 { func GetStaticFloatField(env Env, clazz Class, fieldID FieldID) float32 {
value := C._jni_GetStaticFloatField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticFloatField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return float32(value) return float32(value)
} }
// GetStaticDoubleField looks up the value of a static field of type double. // GetStaticDoubleField looks up the value of a static field of type double.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetStaticDoubleField(env Env, clazz Class, fieldID FieldID) float64 { func GetStaticDoubleField(env Env, clazz Class, fieldID FieldID) float64 {
value := C._jni_GetStaticDoubleField(env.env, C.jclass(clazz), C.jfieldID(fieldID)) value := C._jni_GetStaticDoubleField(env.env, C.jclass(clazz), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return float64(value) return float64(value)
} }
// GetObjectField looks up the value of a static field of type Object. // GetObjectField looks up the value of a static field of type Object.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetObjectField(env Env, obj Object, fieldID FieldID) Object { func GetObjectField(env Env, obj Object, fieldID FieldID) Object {
value := C._jni_GetObjectField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetObjectField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return Object(value) return Object(value)
} }
// GetBooleanField looks up the value of a static field of type boolean. // GetBooleanField looks up the value of a static field of type boolean.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetBooleanField(env Env, obj Object, fieldID FieldID) bool { func GetBooleanField(env Env, obj Object, fieldID FieldID) bool {
value := C._jni_GetBooleanField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetBooleanField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return value != 0 return value != 0
} }
// GetByteField looks up the value of a static field of type byte. // GetByteField looks up the value of a static field of type byte.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetByteField(env Env, obj Object, fieldID FieldID) byte { func GetByteField(env Env, obj Object, fieldID FieldID) byte {
value := C._jni_GetByteField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetByteField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return byte(value) return byte(value)
} }
// GetCharField looks up the value of a static field of type char. // GetCharField looks up the value of a static field of type char.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetCharField(env Env, obj Object, fieldID FieldID) byte { func GetCharField(env Env, obj Object, fieldID FieldID) byte {
value := C._jni_GetCharField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetCharField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return byte(value) return byte(value)
} }
// GetShortField looks up the value of a static field of type short. // GetShortField looks up the value of a static field of type short.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetShortField(env Env, obj Object, fieldID FieldID) int16 { func GetShortField(env Env, obj Object, fieldID FieldID) int16 {
value := C._jni_GetShortField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetShortField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int16(value) return int16(value)
} }
// GetIntField looks up the value of a static field of type int. // GetIntField looks up the value of a static field of type int.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetIntField(env Env, obj Object, fieldID FieldID) int32 { func GetIntField(env Env, obj Object, fieldID FieldID) int32 {
value := C._jni_GetIntField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetIntField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int32(value) return int32(value)
} }
// GetLongField looks up the value of a static field of type long. // GetLongField looks up the value of a static field of type long.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetLongField(env Env, obj Object, fieldID FieldID) int64 { func GetLongField(env Env, obj Object, fieldID FieldID) int64 {
value := C._jni_GetLongField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetLongField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return int64(value) return int64(value)
} }
// GetFloatField looks up the value of a static field of type float. // GetFloatField looks up the value of a static field of type float.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetFloatField(env Env, obj Object, fieldID FieldID) float32 { func GetFloatField(env Env, obj Object, fieldID FieldID) float32 {
value := C._jni_GetFloatField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetFloatField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return float32(value) return float32(value)
} }
// GetDoubleField looks up the value of a static field of type double. // GetDoubleField looks up the value of a static field of type double.
// It panics if it is unable to find the field. // This should never throw an exception.
func GetDoubleField(env Env, obj Object, fieldID FieldID) float64 { func GetDoubleField(env Env, obj Object, fieldID FieldID) float64 {
value := C._jni_GetDoubleField(env.env, C.jobject(obj), C.jfieldID(fieldID)) value := C._jni_GetDoubleField(env.env, C.jobject(obj), C.jfieldID(fieldID))
if err := exception(env); err != nil {
panic(err)
}
return float64(value) return float64(value)
} }

View File

@ -9,29 +9,13 @@ package jni
*/ */
import "C" import "C"
import (
"unsafe"
)
// CreateJavaVM creates a new Java VM with the options specified (if any). // 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 // This should not be called more than once as it can result in an error if
// a JVM already exists for a given process. // a JVM already exists for a given process.
// //
// This is not implemented on Android and is therefore excluded on that // This is not implemented on Android and is therefore excluded on that
// platform by build flags and C. // platform by build flags and C.
func CreateJavaVM(opts ...string) JVM { func CreateJavaVM() JVM {
nOptions := len(opts) jvm := C._jni_CreateJavaVM((**C.char)(nil), 0)
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 } return JVM{ jvm: jvm }
} }

View File

@ -1,11 +1,12 @@
// +build !android // +build !android
//go:generate javac test/AClass.java //go:generate javac test/AClass.java test/AClass2.java
package jni package jni
import ( import (
"sync" "sync"
"testing" "testing"
"unsafe"
) )
var ( var (
@ -25,6 +26,17 @@ func TestCreateJVM(t *testing.T) {
}) })
} }
func TestDo(t *testing.T) {
// create an invalid JVM
vm2 := JVMFor(uintptr(unsafe.Pointer(vm.jvm)))
err := Do(vm2, func(env Env) error {
return nil
})
if err != nil {
t.Errorf("Do() returned an error")
}
}
func TestFindClass(t *testing.T) { func TestFindClass(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
@ -36,6 +48,34 @@ func TestFindClass(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Error: %s", err) t.Errorf("Error: %s", err)
} }
defer func() {
if r := recover(); r == nil {
t.Errorf("No exception for class not found")
} else {
t.Logf("Panic: %s", r)
}
}()
err = Do(vm, func(env Env) error {
cls := FindClass(env, "test/NoSuchClass")
if cls == 0 {
t.Errorf("Class is nil")
}
return nil
})
}
func TestEnvFor(t *testing.T) {
err := Do(vm, func(env Env) error {
env2 := EnvFor(uintptr(unsafe.Pointer(env.env)))
cls := FindClass(env2, "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) { func TestGetMethodID(t *testing.T) {
@ -67,6 +107,7 @@ func TestNewObject(t *testing.T) {
if inst == 0 { if inst == 0 {
t.Errorf("NewGlobalRef returned nil") t.Errorf("NewGlobalRef returned nil")
} }
DeleteGlobalRef(env, inst)
return nil return nil
}) })
if err != nil { if err != nil {
@ -93,6 +134,7 @@ func TestIsSameObject(t *testing.T) {
if !IsSameObject(env, inst, inst2) { if !IsSameObject(env, inst, inst2) {
t.Errorf("New local ref is not the same as original object") t.Errorf("New local ref is not the same as original object")
} }
DeleteLocalRef(env, inst)
return nil return nil
}) })
if err != nil { if err != nil {
@ -100,6 +142,21 @@ func TestIsSameObject(t *testing.T) {
} }
} }
func TestStaticMethod(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("GetStaticMethodID() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
GetStaticMethodID(env, cls, "noSuchMethod", "()V")
return nil
})
}
func TestStaticIntMethod(t *testing.T) { func TestStaticIntMethod(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
@ -122,6 +179,25 @@ func TestStaticIntMethod(t *testing.T) {
} }
} }
func TestStaticObjectMethod(t *testing.T) {
err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V")
mid = GetStaticMethodID(env, cls, "GetStaticObject", "()Ljava/lang/Object;")
if mid == nil {
t.Errorf("MethodID is nil")
}
_, err := CallStaticObjectMethod(env, cls, mid)
if err != nil {
t.Errorf("Method invocation failed")
}
return err
})
if err != nil {
t.Errorf("Error: %s", err)
}
}
func TestStaticBooleanMethod(t *testing.T) { func TestStaticBooleanMethod(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
@ -150,6 +226,9 @@ func TestStaticBooleanMethod(t *testing.T) {
if res { if res {
t.Errorf("Method returned %v, not expected value of %v.", res, false) t.Errorf("Method returned %v, not expected value of %v.", res, false)
} }
if err := CallStaticVoidMethod(env, cls, setterMid, TRUE); err != nil {
t.Errorf("Setter invocation failed")
}
return err return err
}) })
if err != nil { if err != nil {
@ -157,6 +236,21 @@ func TestStaticBooleanMethod(t *testing.T) {
} }
} }
func TestMethod(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("GetMethodID() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
GetMethodID(env, cls, "noSuchMethod", "()V")
return nil
})
}
func TestIntMethod(t *testing.T) { func TestIntMethod(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
@ -170,7 +264,7 @@ func TestIntMethod(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Method invocation failed") t.Errorf("Method invocation failed")
} }
if res != 0 { if res != 101 {
t.Errorf("Method returned %d, not expected value of %d.", res, 0) t.Errorf("Method returned %d, not expected value of %d.", res, 0)
} }
return nil return nil
@ -354,14 +448,6 @@ func TestVoidMethod(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Method invocation failed") 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 return nil
}) })
if err != nil { if err != nil {
@ -457,6 +543,23 @@ func TestStaticVoidMethod(t *testing.T) {
} }
func TestGetObjectClass(t *testing.T) { func TestGetObjectClass(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("GetObjectClass() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
err := Do(vm, func(env Env) error {
GetObjectClass(env, Object(unsafe.Pointer(uintptr(0))))
return nil
})
if err != nil {
t.Errorf("Error: %s", err)
}
}
func TestGetObjectClass2(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V") mid := GetMethodID(env, cls, "<init>", "()V")
@ -475,18 +578,51 @@ func TestGetObjectClass(t *testing.T) {
} }
} }
func TestField(t *testing.T) { func TestIsInstanceOf(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("IsInstanceOf() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
err := Do(vm, func(env Env) error {
IsInstanceOf(env, Object(0), Class(0))
return nil
})
if err != nil {
t.Errorf("Error: %s", err)
}
}
func TestIsInstanceOf2(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("IsInstanceOf() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V") mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid) inst, _ := NewObject(env, cls, mid)
fid := GetFieldID(env, cls, "intval", "I") IsInstanceOf(env, inst, Class(0))
if fid == nil { return nil
t.Errorf("FieldID is nil") })
} if err != nil {
res := GetIntField(env, inst, fid) t.Errorf("Error: %s", err)
if res != 0 { }
t.Errorf("Method returned %d, not expected value of %d.", res, 0) }
func TestIsInstanceOf3(t *testing.T) {
err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
cls = FindClass(env, "java/lang/String")
if IsInstanceOf(env, inst, cls) {
t.Errorf("IsInstanceOf() returned wrong value")
} }
return nil return nil
}) })
@ -495,16 +631,82 @@ func TestField(t *testing.T) {
} }
} }
func TestStaticField(t *testing.T) { func TestField(t *testing.T) {
err := Do(vm, func(env Env) error { err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass") cls := FindClass(env, "test/AClass")
fid := GetStaticFieldID(env, cls, "staticintval", "I") mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
fid := GetFieldID(env, cls, "in", "I")
if fid == nil { if fid == nil {
t.Errorf("FieldID is nil") t.Errorf("FieldID is nil")
} }
res := GetStaticIntField(env, cls, fid) r1 := GetIntField(env, inst, fid)
if res != 100 { if r1 != 101 {
t.Errorf("Method returned %d, not expected value of %d.", res, 100) t.Errorf("Method returned %d, not expected value of %d.", r1, 0)
}
fid = GetFieldID(env, cls, "bl", "Z")
if fid == nil {
t.Errorf("FieldID is nil")
}
r2 := GetBooleanField(env, inst, fid)
if r2 != false {
t.Errorf("Boolean field value is incorrect")
}
fid = GetFieldID(env, cls, "bt", "B")
if fid == nil {
t.Errorf("FieldID is nil")
}
r3 := GetByteField(env, inst, fid)
if r3 != 'c' {
t.Errorf("Byte field value is incorrect")
}
fid = GetFieldID(env, cls, "ch", "C")
if fid == nil {
t.Errorf("FieldID is nil")
}
r4 := GetCharField(env, inst, fid)
if r4 != 'd' {
t.Errorf("Char field value is incorrect")
}
fid = GetFieldID(env, cls, "obj", "Ljava/lang/Object;")
if fid == nil {
t.Errorf("FieldID is nil")
}
r5 := GetObjectField(env, inst, fid)
if r5 == 0 {
t.Errorf("Object field value is incorrect")
}
fid = GetFieldID(env, cls, "sh", "S")
if fid == nil {
t.Errorf("FieldID is nil")
}
r6 := GetShortField(env, inst, fid)
if r6 != 11 {
t.Errorf("Short field value is incorrect")
}
fid = GetFieldID(env, cls, "lo", "J")
if fid == nil {
t.Errorf("FieldID is nil")
}
r7 := GetLongField(env, inst, fid)
if r7 != 1001 {
t.Errorf("Long field value is incorrect")
}
fid = GetFieldID(env, cls, "fl", "F")
if fid == nil {
t.Errorf("FieldID is nil")
}
r8 := GetFloatField(env, inst, fid)
if r8 != 2.2 {
t.Errorf("Float field value is incorrect")
}
fid = GetFieldID(env, cls, "db", "D")
if fid == nil {
t.Errorf("FieldID is nil")
}
r9 := GetDoubleField(env, inst, fid)
if r9 != 1001.1001 {
t.Errorf("Double field value is incorrect")
} }
return nil return nil
}) })
@ -512,3 +714,304 @@ func TestStaticField(t *testing.T) {
t.Errorf("Error: %s", err) t.Errorf("Error: %s", err)
} }
} }
func TestField2(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("GetFieldID() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
GetFieldID(env, cls, "noSuchField", "I")
return nil
})
}
func TestStaticField(t *testing.T) {
err := Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
fid := GetStaticFieldID(env, cls, "staticint", "I")
if fid == nil {
t.Errorf("FieldID is nil")
}
r1 := GetStaticIntField(env, cls, fid)
if r1 != 100 {
t.Errorf("Method returned %d, not expected value of %d.", r1, 100)
}
fid = GetStaticFieldID(env, cls, "staticbl", "Z")
if fid == nil {
t.Errorf("FieldID is nil")
}
r2 := GetStaticBooleanField(env, cls, fid)
if r2 != true {
t.Errorf("Boolean field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticbt", "B")
if fid == nil {
t.Errorf("FieldID is nil")
}
r3 := GetStaticByteField(env, cls, fid)
if r3 != 'a' {
t.Errorf("Byte field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticch", "C")
if fid == nil {
t.Errorf("FieldID is nil")
}
r4 := GetStaticCharField(env, cls, fid)
if r4 != 'b' {
t.Errorf("Char field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticobj", "Ljava/lang/Object;")
if fid == nil {
t.Errorf("FieldID is nil")
}
r5 := GetStaticObjectField(env, cls, fid)
if r5 == 0 {
t.Errorf("Object field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticsh", "S")
if fid == nil {
t.Errorf("FieldID is nil")
}
r6 := GetStaticShortField(env, cls, fid)
if r6 != 10 {
t.Errorf("Short field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticlo", "J")
if fid == nil {
t.Errorf("FieldID is nil")
}
r7 := GetStaticLongField(env, cls, fid)
if r7 != 1000 {
t.Errorf("Long field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticfl", "F")
if fid == nil {
t.Errorf("FieldID is nil")
}
r8 := GetStaticFloatField(env, cls, fid)
if r8 != 1.1 {
t.Errorf("Float field value is incorrect")
}
fid = GetStaticFieldID(env, cls, "staticdb", "D")
if fid == nil {
t.Errorf("FieldID is nil")
}
r9 := GetStaticDoubleField(env, cls, fid)
if r9 != 1000.0001 {
t.Errorf("Double field value is incorrect")
}
return nil
})
if err != nil {
t.Errorf("Error: %s", err)
}
}
func TestStaticField2(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("GetStaticField() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
fid := GetStaticFieldID(env, cls, "FieldNotFound", "I")
GetStaticIntField(env, cls, fid)
return nil
})
}
func TestByteArray(t *testing.T) {
arr := []byte{'a', 'b', 'c'}
Do(vm, func(env Env) error {
jarr := NewByteArray(env, arr)
arr2 := GetByteArrayElements(env, jarr)
if arr2[0] != 'a' ||
arr2[1] != 'b' ||
arr2[2] != 'c' ||
len(arr2) != 3 {
t.Errorf("GetByteArrayElements() failed")
}
return nil
})
}
func TestObjectArray(t *testing.T) {
Do(vm, func(env Env) error {
cls := FindClass(env, "java/lang/Object")
if cls == 0 {
t.Errorf("Class is nil")
}
strings := []string{
"item1",
"item2",
}
arr := NewObjectArray(env, Size(len(strings)), cls, 0)
for i, s := range strings {
jstring := JavaString(env, s)
err := SetObjectArrayElement(env, arr, Size(i), Object(jstring))
if err != nil {
t.Errorf("SetObjectArrayElement at index %d raised exception", i)
}
}
for i, s := range strings {
r, err := GetObjectArrayElement(env, arr, Size(i))
if err != nil {
t.Errorf("GetObjectArrayElement at index %d raised exception", i)
}
retrieved := GoString(env, String(r))
if s != retrieved {
t.Errorf("Expected item %d to be '%s' but instead was '%s'", i, s, retrieved)
}
}
return nil
})
}
func TestClassLoaderFor(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("ClassLoaderFor() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "java/lang/Object")
if cls == 0 {
t.Errorf("Class is nil")
}
mid := GetMethodID(env, cls, "<init>", "()V")
if mid == nil {
t.Errorf("Method ID is nil")
}
inst, err := NewObject(env, cls, mid)
if err != nil {
t.Errorf("NewObject raised exception")
}
if inst == 0 {
t.Errorf("NewObject returned nil")
}
ClassLoaderFor(env, inst)
return nil
})
}
func TestClassLoaderFor2(t *testing.T) {
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
cl := ClassLoaderFor(env, inst)
if cl == 0 {
t.Errorf("ClassLoaderFor() returned nil")
}
return nil
})
}
func TestClassLoaderFor3(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("ClassLoaderFor() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "java/lang/Object")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
cl := ClassLoaderFor(env, inst)
if cl == 0 {
t.Errorf("ClassLoaderFor() returned nil")
}
return nil
})
}
func TestClassLoaderFor4(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("ClassLoaderFor() did not panic")
} else {
t.Logf("Panic: %s", r)
}
}()
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass2")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
cl := ClassLoaderFor(env, inst)
if cl == 0 {
t.Errorf("ClassLoaderFor() returned nil")
}
return nil
})
}
func TestLoadClass(t *testing.T) {
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
cl := ClassLoaderFor(env, inst)
if cl == 0 {
t.Errorf("ClassLoaderFor() returned nil")
}
cls, err := LoadClass(env, cl, "java.lang.String")
if err != nil {
t.Errorf("LoadClass() returned error: %s", err)
}
if cls == 0 {
t.Errorf("LoadClass() failed")
}
return nil
})
}
func TestLoadClass2(t *testing.T) {
Do(vm, func(env Env) error {
cls := FindClass(env, "test/AClass")
mid := GetMethodID(env, cls, "<init>", "()V")
inst, _ := NewObject(env, cls, mid)
_, err := LoadClass(env, inst, "java.lang.String")
if err == nil {
t.Errorf("LoadClass() did not return an error")
} else {
t.Logf("Error: %s", err)
}
return nil
})
}
func TestJavaString(t *testing.T) {
Do(vm, func(env Env) error {
jstr := JavaString(env, "")
if jstr != 0 {
t.Errorf("String is not nil")
}
gstr := GoString(env, jstr)
if gstr != "" {
t.Errorf("String is not empty")
}
jstr = JavaString(env, "test string")
gstr = GoString(env, jstr)
if gstr != "test string" {
t.Errorf("Strings do not match")
}
return nil
})
}

View File

@ -1,8 +1,14 @@
#!/bin/bash #!/bin/bash
JAVA_HOME=$(dirname $(readlink -f $(which java) | sed 's^jre/bin/^^')) if [ -z ${JAVA_HOME+x} ]
then
# JAVA_HOME not set. Figure out what to use for it.
JAVA_HOME=$(dirname $(readlink -f $(which java) | sed 's^jre/bin/^^'))
# Handle the case where java is being run from the jdk itself, not from within the jre
JAVA_HOME=$(echo $JAVA_HOME | sed 's^/bin^^')
fi
echo // +build linux > jni_linux.tmp echo // +build linux,!android > jni_linux.tmp
echo //Generated by scripts/find_linux_jnih >> jni_linux.tmp echo //Generated by scripts/find_linux_jnih >> jni_linux.tmp
echo >> jni_linux.tmp echo >> jni_linux.tmp
echo package jni >> jni_linux.tmp echo package jni >> jni_linux.tmp

Binary file not shown.

View File

@ -1,33 +1,90 @@
package test; package test;
import java.lang.Class;
import java.lang.ClassLoader;
import java.lang.Exception;
import java.lang.Object;
import java.lang.String;
public class AClass { public class AClass {
public static int staticintval = 100; public static Object staticobj = new Object();
public static boolean staticboolval = true; public static boolean staticbl = true;
public static byte staticbt = 'a';
public static char staticch = 'b';
public static short staticsh = 10;
public static int staticint = 100;
public static long staticlo = 1000;
public static float staticfl = (float)1.1;
public static double staticdb = 1000.0001;
public int intval = 0; private static Object pstaticobj = new Object();
private static boolean pstaticbl = true;
private static byte pstaticbt = 'a';
private static char pstaticch = 'b';
private static short pstaticsh = 10;
private static int pstaticint = 100;
private static long pstaticlo = 1000;
private static float pstaticfl = (float)1.1;
private static double pstaticdb = 1000.0001;
public static int GetStaticInt() { public Object obj = new Object();
return staticintval; public boolean bl = false;
} public byte bt = 'c';
public char ch = 'd';
public short sh = 11;
public int in = 101;
public long lo = 1001;
public float fl = (float)2.2;
public double db = 1001.1001;
private Object pobj = new Object();
private boolean pbl = false;
private byte pbt = 'c';
private char pch = 'd';
private short psh = 11;
private int pin = 101;
private long plo = 1001;
private float pfl = (float)2.2;
private double pdb = 1001.1001;
public static boolean GetStaticBoolean() { public static boolean GetStaticBoolean() {
return staticboolval; return staticbl;
}
public static byte GetStaticByte() {
return staticbt;
}
public static char GetStaticChar() {
return staticch;
}
public static short GetStaticShort() {
return staticsh;
}
public static int GetStaticInt() {
return staticint;
} }
public static void SetStaticInt(int val) { public static void SetStaticInt(int val) {
staticintval = val; staticint = val;
}
public static Object GetStaticObject() {
return staticobj;
} }
public static void SetStaticBoolean(boolean val) { public static void SetStaticBoolean(boolean val) {
staticboolval = val; staticbl = val;
} }
public void IncInt() { public void IncInt() {
intval = intval + 1; in = in + 1;
} }
public int GetInt() { public int GetInt() {
return intval; return in;
} }
public boolean GetBoolean() { public boolean GetBoolean() {
@ -59,10 +116,18 @@ public class AClass {
} }
public void SetInt(int val) { public void SetInt(int val) {
intval = val; in = val;
} }
public void AddInts(int val1, int val2) { public void AddInts(int val1, int val2) {
intval = val1 + val2; in = val1 + val2;
}
public Class loadClass(String s) throws Exception {
throw new Exception("AClass: loadClass exception");
}
public ClassLoader getClassLoader() {
return this.getClass().getClassLoader();
} }
} }

BIN
test/AClass2.class Normal file

Binary file not shown.

10
test/AClass2.java Normal file
View File

@ -0,0 +1,10 @@
package test;
import java.lang.ClassLoader;
import java.lang.Exception;
public class AClass2 {
public ClassLoader getClassLoader() throws Exception {
throw new Exception("Exception");
}
}