Move to the new call style

Change-Id: Ib909ab750f900013fd08fde050674b3f72fc0298
diff --git a/runtimes/google/ipc/jni/dispatcher.go b/runtimes/google/ipc/jni/dispatcher.go
index b1fff9b..5b86876 100644
--- a/runtimes/google/ipc/jni/dispatcher.go
+++ b/runtimes/google/ipc/jni/dispatcher.go
@@ -14,17 +14,6 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobject CallDispatcherLookupMethod(JNIEnv* env, jobject obj, jmethodID id, jstring str) {
-//   return (*env)->CallObjectMethod(env, obj, id, str);
-// }
-// static jobject CallDispatcherGetObjectMethod(JNIEnv* env, jobject obj, jmethodID id) {
-//   return (*env)->CallObjectMethod(env, obj, id);
-// }
-// static jobject CallDispatcherGetAuthorizerMethod(JNIEnv* env, jobject obj, jmethodID id) {
-//   return (*env)->CallObjectMethod(env, obj, id);
-// }
 import "C"
 
 func newDispatcher(env *C.JNIEnv, jDispatcher C.jobject) (*dispatcher, error) {
@@ -66,29 +55,27 @@
 
 	// Call Java dispatcher's lookup() method.
 	serviceObjectWithAuthorizerSign := util.ClassSign("com.veyron2.ipc.ServiceObjectWithAuthorizer")
-	lid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, d.jDispatcher), "lookup", util.FuncSign([]util.Sign{util.StringSign}, serviceObjectWithAuthorizerSign)))
-	jServiceObjectWithAuthorizer := C.CallDispatcherLookupMethod(env, d.jDispatcher, lid, C.jstring(util.JStringPtr(env, suffix)))
-	if err := util.JExceptionMsg(env); err != nil {
+	tempJObj, err := util.CallObjectMethod(env, d.jDispatcher, "lookup", []util.Sign{util.StringSign}, serviceObjectWithAuthorizerSign, suffix)
+	jObj := C.jobject(tempJObj)
+	if err != nil {
 		return nil, nil, fmt.Errorf("error invoking Java dispatcher's lookup() method: %v", err)
 	}
-	if jServiceObjectWithAuthorizer == nil {
+	if jObj == nil {
 		// Lookup returned null, which means that the dispatcher isn't handling the object -
 		// this is not an error.
 		return nil, nil, nil
 	}
 
 	// Extract the Java service object and Authorizer.
-	oid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, jServiceObjectWithAuthorizer), "getServiceObject", util.FuncSign(nil, util.ObjectSign)))
-	jObj := C.CallDispatcherGetObjectMethod(env, jServiceObjectWithAuthorizer, oid)
-	if jObj == nil {
+	jServiceObj := C.jobject(util.CallObjectMethodOrCatch(env, jObj, "getServiceObject", nil, util.ObjectSign))
+	if jServiceObj == nil {
 		return nil, nil, fmt.Errorf("null service object returned by Java's ServiceObjectWithAuthorizer")
 	}
 	authSign := util.ClassSign("com.veyron2.security.Authorizer")
-	aid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, jServiceObjectWithAuthorizer), "getAuthorizer", util.FuncSign(nil, authSign)))
-	jAuth := C.CallDispatcherGetAuthorizerMethod(env, jServiceObjectWithAuthorizer, aid)
+	jAuth := C.jobject(util.CallObjectMethodOrCatch(env, jObj, "getAuthorizer", nil, authSign))
 
 	// Create Go Invoker and Authorizer.
-	i, err := newInvoker(env, d.jVM, jObj)
+	i, err := newInvoker(env, d.jVM, jServiceObj)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/runtimes/google/ipc/jni/invoker.go b/runtimes/google/ipc/jni/invoker.go
index 8086cf1..f9f2f6d 100644
--- a/runtimes/google/ipc/jni/invoker.go
+++ b/runtimes/google/ipc/jni/invoker.go
@@ -19,12 +19,13 @@
 
 func newInvoker(env *C.JNIEnv, jVM *C.JavaVM, jObj C.jobject) (*invoker, error) {
 	// Create a new Java VDLInvoker object.
-	jInvoker := C.jobject(util.NewObject(env, jVDLInvokerClass, []util.Sign{util.ObjectSign}, jObj))
-	if err := util.JExceptionMsg(env); err != nil {
+	tempJInvoker, err := util.NewObject(env, jVDLInvokerClass, []util.Sign{util.ObjectSign}, jObj)
+	jInvoker := C.jobject(tempJInvoker)
+	if err != nil {
 		return nil, fmt.Errorf("error creating Java VDLInvoker object: %v", err)
 	}
 	// Fetch the argGetter for the object.
-	jPathArray := C.jobjectArray(util.CallObjectMethod(env, jInvoker, "getImplementedServices", nil, util.ArraySign(util.StringSign)))
+	jPathArray := C.jobjectArray(util.CallObjectMethodOrCatch(env, jInvoker, "getImplementedServices", nil, util.ArraySign(util.StringSign)))
 	paths := util.GoStringArray(env, jPathArray)
 	getter, err := newArgGetter(paths)
 	if err != nil {
@@ -73,9 +74,9 @@
 
 	// Get the security label.
 	labelSign := util.ClassSign("com.veyron2.security.Label")
-	jLabel := C.jobject(util.CallObjectMethod(env, i.jInvoker, "getSecurityLabel", []util.Sign{util.StringSign}, labelSign, util.CamelCase(method)))
-	if err = util.JExceptionMsg(env); err != nil {
-		return
+	jLabel, err := util.CallObjectMethod(env, i.jInvoker, "getSecurityLabel", []util.Sign{util.StringSign}, labelSign, util.CamelCase(method))
+	if err != nil {
+		return nil, security.Label(0), err
 	}
 	label = security.Label(util.JIntField(env, jLabel, "value"))
 	return
@@ -99,7 +100,7 @@
 		err = fmt.Errorf("couldn't find VDL method %q with %d args", method, len(argptrs))
 	}
 	sCall := newServerCall(call, mArgs)
-	jServerCall := C.jobject(util.NewObject(env, jServerCallClass, []util.Sign{util.LongSign}, sCall))
+	jServerCall := C.jobject(util.NewObjectOrCatch(env, jServerCallClass, []util.Sign{util.LongSign}, sCall))
 	util.GoRef(sCall) // unref-ed when jServerCall is garbage-collected
 
 	// Translate input args to JSON.
@@ -110,12 +111,12 @@
 	// Invoke the method.
 	callSign := util.ClassSign("com.veyron2.ipc.ServerCall")
 	replySign := util.ClassSign("com.veyron.runtimes.google.VDLInvoker$InvokeReply")
-	jReply := C.jobject(util.CallObjectMethod(env, i.jInvoker, "invoke", []util.Sign{util.StringSign, callSign, util.ArraySign(util.StringSign)}, replySign, util.CamelCase(method), jServerCall, jArgs))
-	if err := util.JExceptionMsg(env); err != nil {
+	jReply, err := util.CallObjectMethod(env, i.jInvoker, "invoke", []util.Sign{util.StringSign, callSign, util.ArraySign(util.StringSign)}, replySign, util.CamelCase(method), jServerCall, jArgs)
+	if err != nil {
 		return nil, fmt.Errorf("error invoking Java method %q: %v", method, err)
 	}
 	// Decode and return results.
-	return i.decodeResults(env, method, len(argptrs), jReply)
+	return i.decodeResults(env, method, len(argptrs), C.jobject(jReply))
 }
 
 // encodeArgs JSON-encodes the provided argument pointers, converts them into
diff --git a/runtimes/google/jni/jni.go b/runtimes/google/jni/jni.go
index 4df2de1..9c9e462 100644
--- a/runtimes/google/jni/jni.go
+++ b/runtimes/google/jni/jni.go
@@ -25,18 +25,9 @@
 		C.AttachCurrentThread(jVM, &env, nil)
 		defer C.DetachCurrentThread(jVM)
 	}
-	log.Println("Here1")
 	util.Init(env)
-	log.Println("Here2")
 	ipc.Init(env)
-	log.Println("Here3")
 	security.Init(env)
-	log.Println("Here4")
-	log.Println("Here4")
-	log.Println("Here4")
-	log.Println("Here4")
-	log.Println("Here4")
-	log.Println("Here4")
 	return C.JNI_VERSION_1_6
 }
 
diff --git a/runtimes/google/jni/util/call.go b/runtimes/google/jni/util/call.go
index 5c1e694..72e8614 100644
--- a/runtimes/google/jni/util/call.go
+++ b/runtimes/google/jni/util/call.go
@@ -42,6 +42,20 @@
 			panic("JStringPtr failed to convert string.")
 		}
 		ptr = unsafe.Pointer(&jv)
+	case reflect.Slice, reflect.Array:
+		switch rv.Type().Elem().Kind() {
+		case reflect.Uint8:
+			bs := rv.Interface().([]byte)
+			jv := JByteArrayPtr(env, bs)
+			ptr = unsafe.Pointer(&jv)
+		case reflect.String:
+			// TODO(bprosnitz) We should handle objects by calling jValue recursively. We need a way to get the sign of the target type or treat it as an Object for non-string types.
+			strs := rv.Interface().([]string)
+			jv := JStringArrayPtr(env, strs)
+			ptr = unsafe.Pointer(&jv)
+		default:
+			panic(fmt.Sprintf("support for converting slice of kind %v not yet implemented", rv.Type().Elem().Kind()))
+		}
 	default:
 		panic(fmt.Sprintf("support for converting go value of kind %v not yet implemented", rv.Kind()))
 	}
@@ -66,7 +80,7 @@
 }
 
 // NewObject calls a java constructor through JNI, passing the specified args.
-func NewObject(env interface{}, class interface{}, argSigns []Sign, args ...interface{}) C.jobject {
+func NewObject(env interface{}, class interface{}, argSigns []Sign, args ...interface{}) (C.jobject, error) {
 	if class == nil {
 		panic("cannot call constructor of nil class")
 	}
@@ -78,7 +92,18 @@
 	valArray, freeFunc := jValueArray(jenv, args)
 	defer freeFunc()
 
-	return C.NewObjectA(jenv, jclass, jcid, valArray)
+	ret := C.NewObjectA(jenv, jclass, jcid, valArray)
+	err := JExceptionMsg(env)
+	return ret, err
+}
+
+// NewObjectOrCatch is a helper method that calls NewObject and panics if a Java exception occurred.
+func NewObjectOrCatch(env interface{}, class interface{}, argSigns []Sign, args ...interface{}) C.jobject {
+	obj, err := NewObject(env, class, argSigns, args...)
+	if err != nil {
+		panic(fmt.Sprintf("exception while creating jni object: %v", err))
+	}
+	return obj
 }
 
 // setupMethodCall performs the shared preparation operations between various java method invocation functions.
@@ -94,38 +119,145 @@
 }
 
 // CallObjectMethod calls a java method over JNI that returns a java object.
-func CallObjectMethod(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) C.jobject {
+func CallObjectMethod(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) (C.jobject, error) {
 	switch retSign {
 	case ByteSign, CharSign, ShortSign, LongSign, FloatSign, DoubleSign, BoolSign, IntSign, VoidSign:
 		panic(fmt.Sprintf("Illegal call to CallObjectMethod on method with return sign %s", retSign))
 	}
 	jenv, jobject, jmid, valArray, freeFunc := setupMethodCall(env, object, name, argSigns, retSign, args)
 	defer freeFunc()
-	return C.CallObjectMethodA(jenv, jobject, jmid, valArray)
+	ret := C.CallObjectMethodA(jenv, jobject, jmid, valArray)
+	return ret, JExceptionMsg(env)
 }
 
 // CallStringMethod calls a java method over JNI that returns a string.
-func CallStringMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) string {
-	return GoString(env, CallObjectMethod(env, object, name, argSigns, StringSign, args))
+func CallStringMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) (string, error) {
+	jstr, err := CallObjectMethod(env, object, name, argSigns, StringSign, args)
+	return GoString(env, jstr), err
+}
+
+// CallObjectArrayMethod calls a java method over JNI that returns an object array.
+func CallObjectArrayMethod(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) ([]C.jobject, error) {
+	if retSign == "" || retSign[0] != '[' {
+		panic(fmt.Sprintf("Expected object array, got: %v", retSign))
+	}
+	jenv := getEnv(env)
+	jarr, err := CallObjectMethod(env, object, name, argSigns, retSign, args...)
+	garr := make([]C.jobject, int(C.GetArrayLength(jenv, C.jarray(jarr))))
+	for i, _ := range garr {
+		garr[i] = C.jobject(C.GetObjectArrayElement(jenv, C.jobjectArray(jarr), C.jsize(i)))
+	}
+	return garr, err
+}
+
+// CallStringArrayMethod calls a java method over JNI that returns an string array.
+func CallStringArrayMethod(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) ([]string, error) {
+	objarr, err := CallObjectArrayMethod(env, object, name, argSigns, retSign, args...)
+	strs := make([]string, len(objarr))
+	for i, obj := range objarr {
+		strs[i] = GoString(env, obj)
+	}
+	return strs, err
 }
 
 // CallBooleanMethod calls a java method over JNI that returns a boolean.
-func CallBooleanMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) bool {
+func CallBooleanMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) (bool, error) {
 	jenv, jobject, jmid, valArray, freeFunc := setupMethodCall(env, object, name, argSigns, BoolSign, args)
 	defer freeFunc()
-	return C.CallBooleanMethodA(jenv, jobject, jmid, valArray) != C.JNI_OK
+	ret := C.CallBooleanMethodA(jenv, jobject, jmid, valArray) != C.JNI_OK
+	return ret, JExceptionMsg(env)
 }
 
 // CallIntMethod calls a java method over JNI that returns an int.
-func CallIntMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) int {
+func CallIntMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) (int, error) {
 	jenv, jobject, jmid, valArray, freeFunc := setupMethodCall(env, object, name, argSigns, IntSign, args)
 	defer freeFunc()
-	return int(C.CallIntMethodA(jenv, jobject, jmid, valArray))
+	ret := int(C.CallIntMethodA(jenv, jobject, jmid, valArray))
+	return ret, JExceptionMsg(env)
 }
 
 // CallVoidMethod calls a java method over JNI that "returns" void.
-func CallVoidMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) {
+func CallVoidMethod(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) error {
 	jenv, jobject, jmid, valArray, freeFunc := setupMethodCall(env, object, name, argSigns, VoidSign, args)
 	C.CallVoidMethodA(jenv, jobject, jmid, valArray)
 	freeFunc()
+	return JExceptionMsg(env)
+}
+
+// CallObjectMethodOrCatch is a helper method that calls CallObjectMethod and panics if a Java exception occurred.
+func CallObjectMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) C.jobject {
+	obj, err := CallObjectMethod(env, object, name, argSigns, retSign, args...)
+	handleException(name, err)
+	return obj
+}
+
+// CallStringMethodOrCatch is a helper method that calls CallStringMethod and panics if a Java exception occurred.
+func CallStringMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) string {
+	str, err := CallStringMethod(env, object, name, argSigns, args...)
+	handleException(name, err)
+	return str
+}
+
+// CallObjectArrayMethodOrCatch is a helper method that calls CallObjectArrayMethod and panics if a Java exception occurred.
+func CallObjectArrayMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) []C.jobject {
+	objs, err := CallObjectArrayMethod(env, object, name, argSigns, retSign, args...)
+	handleException(name, err)
+	return objs
+}
+
+// CallStringArrayMethodOrCatch is a helper method that calls CallStringArrayMethod and panics if a Java exception occurred.
+func CallStringArrayMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) []string {
+	strs, err := CallStringArrayMethod(env, object, name, argSigns, ArraySign(StringSign), args...)
+	handleException(name, err)
+	return strs
+}
+
+// CallBooleanMethodOrCatch is a helper method that calls CallBooleanMethod and panics if a Java exception occurred.
+func CallBooleanMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) bool {
+	b, err := CallBooleanMethod(env, object, name, argSigns, args...)
+	handleException(name, err)
+	return b
+}
+
+// CallIntMethodOrCatch is a helper method that calls CallIntMethod and panics if a Java exception occurred.
+func CallIntMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) int {
+	i, err := CallIntMethod(env, object, name, argSigns, args...)
+	handleException(name, err)
+	return i
+}
+
+// CallVoidMethodOrCatch is a helper method that calls CallVoidMethod and panics if a Java exception occurred.
+func CallVoidMethodOrCatch(env interface{}, object interface{}, name string, argSigns []Sign, args ...interface{}) {
+	err := CallVoidMethod(env, object, name, argSigns, args...)
+	handleException(name, err)
+}
+
+// CallStaticObjectMethod calls a static java method over JNI that returns a java object.
+func CallStaticObjectMethod(env interface{}, class interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) (C.jobject, error) {
+	switch retSign {
+	case ByteSign, CharSign, ShortSign, LongSign, FloatSign, DoubleSign, BoolSign, IntSign, VoidSign:
+		panic(fmt.Sprintf("Illegal call to CallObjectMethod on method with return sign %s", retSign))
+	}
+	jenv := getEnv(env)
+	jclass := getClass(class)
+
+	jmid := C.jmethodID(JMethodIDPtrOrDie(jenv, jclass, name, FuncSign(argSigns, retSign)))
+
+	jvalArray, freeFunc := jValueArray(jenv, args)
+	ret := C.CallStaticObjectMethodA(jenv, jclass, jmid, jvalArray)
+	freeFunc()
+	return ret, JExceptionMsg(env)
+}
+
+// CallStaticObjectMethodOrCatch is a helper method that calls CallStaticObjectMethod and panics if a Java exception occurred.
+func CallStaticObjectMethodOrCatch(env interface{}, class interface{}, name string, argSigns []Sign, retSign Sign, args ...interface{}) C.jobject {
+	obj, err := CallStaticObjectMethod(env, class, name, argSigns, retSign, args...)
+	handleException(name, err)
+	return obj
+}
+
+func handleException(name string, err error) {
+	if err != nil {
+		panic(fmt.Sprintf("exception while calling jni method %q: %v", name, err))
+	}
 }
diff --git a/runtimes/google/security/jni/authorizer.go b/runtimes/google/security/jni/authorizer.go
index d3edf98..aba4213 100644
--- a/runtimes/google/security/jni/authorizer.go
+++ b/runtimes/google/security/jni/authorizer.go
@@ -12,14 +12,6 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobject CallAuthorizerNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
-// 	return (*env)->NewObject(env, class, id, goContextPtr);
-// }
-// static void CallAuthorizerAuthorizeMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
-// 	(*env)->CallObjectMethod(env, obj, id, context);
-// }
 import "C"
 
 // NewAuthorizer returns a new security.Authorizer given the provided Java authorizer.
@@ -63,15 +55,8 @@
 	C.AttachCurrentThread(a.jVM, &env, nil)
 	defer C.DetachCurrentThread(a.jVM)
 	// Create a Java context.
-	util.GoRef(&context) // Un-refed when the Java Context object is finalized.
-	cid := C.jmethodID(util.JMethodIDPtrOrDie(env, jContextImplClass, "<init>", util.FuncSign([]util.Sign{util.LongSign}, util.VoidSign)))
-	jContext := C.CallAuthorizerNewContextObject(env, jContextImplClass, cid, C.jlong(util.PtrValue(&context)))
+	jContext := newJavaContext(env, context)
 	// Run Java Authorizer.
 	contextSign := util.ClassSign("com.veyron2.security.Context")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, a.jAuth), "authorize", util.FuncSign([]util.Sign{contextSign}, util.VoidSign)))
-	C.CallAuthorizerAuthorizeMethod(env, a.jAuth, mid, jContext)
-	if err := util.JExceptionMsg(env); err != nil {
-		return err
-	}
-	return nil
+	return util.CallVoidMethod(env, a.jAuth, "authorize", []util.Sign{contextSign}, util.VoidSign, jContext)
 }
diff --git a/runtimes/google/security/jni/caveat.go b/runtimes/google/security/jni/caveat.go
index 63d83e0..65253d6 100644
--- a/runtimes/google/security/jni/caveat.go
+++ b/runtimes/google/security/jni/caveat.go
@@ -11,15 +11,6 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-//
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobject CallCaveatNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
-// 	return (*env)->NewObject(env, class, id, goContextPtr);
-// }
-// static void CallCaveatValidateMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
-// 	return (*env)->CallVoidMethod(env, obj, id, context);
-// }
 import "C"
 
 func newCaveat(env *C.JNIEnv, jCaveat C.jobject) *caveat {
@@ -56,11 +47,7 @@
 	var env *C.JNIEnv
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
-	util.GoRef(&context) // un-refed when the Java Context object is finalized.
-	cid := C.jmethodID(util.JMethodIDPtrOrDie(env, jContextImplClass, "<init>", util.FuncSign([]util.Sign{util.LongSign}, util.VoidSign)))
-	jContext := C.CallCaveatNewContextObject(env, jContextImplClass, cid, C.jlong(util.PtrValue(&context)))
+	jContext := newJavaContext(env, context)
 	contextSign := util.ClassSign("com.veyron2.security.Context")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jCaveat), "validate", util.FuncSign([]util.Sign{contextSign}, util.VoidSign)))
-	C.CallCaveatValidateMethod(env, c.jCaveat, mid, jContext)
-	return util.JExceptionMsg(env)
+	return util.CallVoidMethod(env, c.jCaveat, "validate", []util.Sign{contextSign}, jContext)
 }
diff --git a/runtimes/google/security/jni/context.go b/runtimes/google/security/jni/context.go
index a6ba6a1..aca55b5 100644
--- a/runtimes/google/security/jni/context.go
+++ b/runtimes/google/security/jni/context.go
@@ -13,23 +13,14 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-//
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jstring CallContextStringMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (jstring)(*env)->CallObjectMethod(env, obj, id);
-// }
-// static jint CallContextIntMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (*env)->CallIntMethod(env, obj, id);
-// }
-// static jobject CallContextPublicIDMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (*env)->CallObjectMethod(env, obj, id);
-// }
-// static jobject CallContextLabelMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (*env)->CallObjectMethod(env, obj, id);
-// }
 import "C"
 
+// newJavaContext constructs a new context in java based on the passed go context.
+func newJavaContext(env interface{}, context security.Context) C.jobject {
+	util.GoRef(&context) // Un-refed when the Java Context object is finalized.
+	return C.jobject(util.NewObjectOrCatch(env, jContextImplClass, []util.Sign{util.LongSign}, &context))
+}
+
 func newContext(env *C.JNIEnv, jContext C.jobject) *context {
 	// We cannot cache Java environments as they are only valid in the current
 	// thread.  We can, however, cache the Java VM and obtain an environment
@@ -55,33 +46,22 @@
 	return c
 }
 
+// context is the go interface to the java implementation of security.Context
 type context struct {
 	jVM      *C.JavaVM
 	jContext C.jobject
 }
 
 func (c *context) Method() string {
-	var env *C.JNIEnv
-	C.AttachCurrentThread(c.jVM, &env, nil)
-	defer C.DetachCurrentThread(c.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "method", util.FuncSign(nil, util.StringSign)))
-	return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+	return c.callStringMethod("method")
 }
 
 func (c *context) Name() string {
-	var env *C.JNIEnv
-	C.AttachCurrentThread(c.jVM, &env, nil)
-	defer C.DetachCurrentThread(c.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "name", util.FuncSign(nil, util.StringSign)))
-	return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+	return c.callStringMethod("name")
 }
 
 func (c *context) Suffix() string {
-	var env *C.JNIEnv
-	C.AttachCurrentThread(c.jVM, &env, nil)
-	defer C.DetachCurrentThread(c.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "suffix", util.FuncSign(nil, util.StringSign)))
-	return util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+	return c.callStringMethod("suffix")
 }
 
 func (c *context) Label() security.Label {
@@ -89,8 +69,7 @@
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
 	labelSign := util.ClassSign("com.veyron2.security.Label")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "label", util.FuncSign(nil, labelSign)))
-	jLabel := C.CallContextLabelMethod(env, c.jContext, mid)
+	jLabel := C.jobject(util.CallObjectMethodOrCatch(env, c.jContext, "label", nil, labelSign))
 	return security.Label(util.JIntField(env, jLabel, "value"))
 }
 
@@ -104,8 +83,7 @@
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
 	publicIDSign := util.ClassSign("com.veyron2.security.PublicID")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "localID", util.FuncSign(nil, publicIDSign)))
-	jID := C.CallContextPublicIDMethod(env, c.jContext, mid)
+	jID := C.jobject(util.CallObjectMethodOrCatch(env, c.jContext, "localID", nil, publicIDSign))
 	return newPublicID(env, jID)
 }
 
@@ -114,8 +92,7 @@
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
 	publicIDSign := util.ClassSign("com.veyron2.security.PublicID")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "remoteID", util.FuncSign(nil, publicIDSign)))
-	jID := C.CallContextPublicIDMethod(env, c.jContext, mid)
+	jID := C.jobject(util.CallObjectMethodOrCatch(env, c.jContext, "remoteID", nil, publicIDSign))
 	return newPublicID(env, jID)
 }
 
@@ -123,9 +100,8 @@
 	var env *C.JNIEnv
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "localEndpoint", util.FuncSign(nil, util.StringSign)))
 	// TODO(spetrovic): create a Java Endpoint interface.
-	epStr := util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+	epStr := util.CallStringMethodOrCatch(env, c.jContext, "localEndpoint", nil)
 	ep, err := inaming.NewEndpoint(epStr)
 	if err != nil {
 		panic("Couldn't parse endpoint string: " + epStr)
@@ -137,12 +113,18 @@
 	var env *C.JNIEnv
 	C.AttachCurrentThread(c.jVM, &env, nil)
 	defer C.DetachCurrentThread(c.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, c.jContext), "remoteEndpoint", util.FuncSign(nil, util.StringSign)))
 	// TODO(spetrovic): create a Java Endpoint interface.
-	epStr := util.GoString(env, C.CallContextStringMethod(env, c.jContext, mid))
+	epStr := util.CallStringMethodOrCatch(env, c.jContext, "remoteEndpoint", nil)
 	ep, err := inaming.NewEndpoint(epStr)
 	if err != nil {
 		panic("Couldn't parse endpoint string: " + epStr)
 	}
 	return ep
 }
+
+func (c *context) callStringMethod(methodName string) string {
+	var env *C.JNIEnv
+	C.AttachCurrentThread(c.jVM, &env, nil)
+	defer C.DetachCurrentThread(c.jVM)
+	return util.CallStringMethodOrCatch(env, c.jContext, methodName, nil)
+}
diff --git a/runtimes/google/security/jni/jni.go b/runtimes/google/security/jni/jni.go
index 2f5c3c2..0803130 100644
--- a/runtimes/google/security/jni/jni.go
+++ b/runtimes/google/security/jni/jni.go
@@ -15,18 +15,6 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-//
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobject CallNewECPublicKeyInfoObject(JNIEnv* env, jclass class, jmethodID id, jbyteArray keyX, jbyteArray keyY, jbyteArray encodedKey, jint fieldBitSize) {
-//   return (*env)->NewObject(env, class, id, keyX, keyY, encodedKey, fieldBitSize);
-// }
-// static jobject CallNewCaveatObject(JNIEnv* env, jclass class, jmethodID id, jlong nativePtr) {
-//   return (*env)->NewObject(env, class, id, nativePtr);
-// }
-// static jobject CallNewServiceCaveatObject(JNIEnv* env, jclass class, jmethodID id, jstring service, jobject caveat) {
-//   return (*env)->NewObject(env, class, id, service, caveat);
-// }
 import "C"
 
 var (
@@ -84,8 +72,7 @@
 		util.JThrowV(env, err)
 		return C.jobject(nil)
 	}
-	cid := C.jmethodID(util.JMethodIDPtrOrDie(env, jECPublicKeyInfoClass, "<init>", util.FuncSign([]util.Sign{util.ArraySign(util.ByteSign), util.ArraySign(util.ByteSign), util.ArraySign(util.ByteSign), util.IntSign}, util.VoidSign)))
-	return C.CallNewECPublicKeyInfoObject(env, jECPublicKeyInfoClass, cid, C.jbyteArray(util.JByteArrayPtr(env, key.X.Bytes())), C.jbyteArray(util.JByteArrayPtr(env, key.Y.Bytes())), C.jbyteArray(util.JByteArrayPtr(env, encoded)), C.jint(key.Params().BitSize))
+	return C.jobject(util.NewObjectOrCatch(env, jECPublicKeyInfoClass, []util.Sign{util.ArraySign(util.ByteSign), util.ArraySign(util.ByteSign), util.ArraySign(util.ByteSign), util.IntSign}, key.X.Bytes(), key.Y.Bytes(), encoded, key.Params().BitSize))
 }
 
 //export Java_com_veyron_runtimes_google_security_PublicID_nativeAuthorize
@@ -106,10 +93,8 @@
 	jServiceCaveats := C.NewObjectArray(env, C.jsize(len(sCaveats)), jServiceCaveatClass, nil)
 	for i, sCaveat := range sCaveats {
 		util.GoRef(&sCaveat) // Un-refed when the Java Caveat object is finalized.
-		cid := C.jmethodID(util.JMethodIDPtrOrDie(env, jCaveatImplClass, "<init>", util.FuncSign([]util.Sign{util.LongSign}, util.VoidSign)))
-		jCaveat := C.CallNewCaveatObject(env, jCaveatImplClass, cid, C.jlong(util.PtrValue(&sCaveat)))
-		scid := C.jmethodID(util.JMethodIDPtrOrDie(env, jServiceCaveatClass, "<init>", util.FuncSign([]util.Sign{util.StringSign, caveatSign}, util.VoidSign)))
-		jServiceCaveat := C.CallNewServiceCaveatObject(env, jServiceCaveatClass, scid, C.jstring(util.JStringPtr(env, string(sCaveat.Service))), jCaveat)
+		jCaveat := C.jobject(util.NewObjectOrCatch(env, jCaveatImplClass, []util.Sign{util.LongSign}, &sCaveat))
+		jServiceCaveat := C.jobject(util.NewObjectOrCatch(env, jServiceCaveatClass, []util.Sign{util.StringSign, caveatSign}, sCaveat.Service, jCaveat))
 		C.SetObjectArrayElement(env, jServiceCaveats, C.jsize(i), jServiceCaveat)
 	}
 	return jServiceCaveats
@@ -132,7 +117,7 @@
 
 //export Java_com_veyron_runtimes_google_security_PrivateID_nativeCreate
 func Java_com_veyron_runtimes_google_security_PrivateID_nativeCreate(env *C.JNIEnv, jPrivateIDClass C.jclass, name C.jstring) C.jlong {
-	id, err := isecurity.NewPrivateID(util.GoString(env, name))
+	id, err := isecurity.NewPrivateID(util.GoString(env, name), nil)
 	if err != nil {
 		util.JThrowV(env, err)
 		return C.jlong(0)
diff --git a/runtimes/google/security/jni/publicid.go b/runtimes/google/security/jni/publicid.go
index 8e0a5fc..8bc4ad6 100644
--- a/runtimes/google/security/jni/publicid.go
+++ b/runtimes/google/security/jni/publicid.go
@@ -14,30 +14,6 @@
 
 // #cgo LDFLAGS: -ljniwrapper
 // #include "jni_wrapper.h"
-//
-// // CGO doesn't support variadic functions so we have to hard-code these
-// // functions to match the invoking code. Ugh!
-// static jobjectArray CallPublicIDNamesMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (jobjectArray)(*env)->CallObjectMethod(env, obj, id);
-// }
-// static jboolean CallPublicIDMatchMethod(JNIEnv* env, jobject obj, jmethodID id, jstring pattern) {
-// 	return (*env)->CallBooleanMethod(env, obj, id, pattern);
-// }
-// static jobject CallPublicIDPublicKeyMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (*env)->CallObjectMethod(env, obj, id);
-// }
-// static jobject CallPublicIDAuthorizeMethod(JNIEnv* env, jobject obj, jmethodID id, jobject context) {
-// 	return (*env)->CallObjectMethod(env, obj, id, context);
-// }
-// static jobjectArray CallPublicIDThirdPartyCaveatsMethod(JNIEnv* env, jobject obj, jmethodID id) {
-// 	return (jobjectArray)(*env)->CallObjectMethod(env, obj, id);
-// }
-// static jobject CallPublicIDNewContextObject(JNIEnv* env, jclass class, jmethodID id, jlong goContextPtr) {
-// 	return (*env)->NewObject(env, class, id, goContextPtr);
-// }
-// static jobject CallPublicIDGetKeyInfoMethod(JNIEnv* env, jclass class, jmethodID id, jobject key) {
-// 	return (*env)->CallStaticObjectMethod(env, class, id, key);
-// }
 import "C"
 
 func newPublicID(env *C.JNIEnv, jPublicID C.jobject) *publicID {
@@ -74,29 +50,21 @@
 	var env *C.JNIEnv
 	C.AttachCurrentThread(id.jVM, &env, nil)
 	defer C.DetachCurrentThread(id.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, id.jPublicID), "names", util.FuncSign(nil, util.ArraySign(util.StringSign))))
-	names := C.CallPublicIDNamesMethod(env, id.jPublicID, mid)
-	ret := make([]string, int(C.GetArrayLength(env, C.jarray(names))))
-	for i := 0; i < len(ret); i++ {
-		ret[i] = util.GoString(env, C.GetObjectArrayElement(env, names, C.jsize(i)))
-	}
-	return ret
+	return util.CallStringArrayMethodOrCatch(env, id.jPublicID, "names", nil)
 }
 
 func (id *publicID) Match(pattern security.PrincipalPattern) bool {
 	var env *C.JNIEnv
 	C.AttachCurrentThread(id.jVM, &env, nil)
 	defer C.DetachCurrentThread(id.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, id.jPublicID), "match", util.FuncSign([]util.Sign{util.StringSign}, util.BoolSign)))
-	return C.CallPublicIDMatchMethod(env, id.jPublicID, mid, C.jstring(util.JStringPtr(env, string(pattern)))) == C.JNI_TRUE
+	return util.CallBooleanMethodOrCatch(env, id.jPublicID, "match", []util.Sign{util.StringSign})
 }
 
 func (id *publicID) PublicKey() *ecdsa.PublicKey {
 	var env *C.JNIEnv
 	C.AttachCurrentThread(id.jVM, &env, nil)
 	defer C.DetachCurrentThread(id.jVM)
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, id.jPublicID), "publicKey", util.FuncSign(nil, util.ObjectSign)))
-	jPublicKey := C.CallPublicIDPublicKeyMethod(env, id.jPublicID, mid)
+	jPublicKey := C.jobject(util.CallObjectMethodOrCatch(env, id.jPublicID, "publicKey", nil, util.ObjectSign))
 	return newPublicKey(env, jPublicKey)
 }
 
@@ -104,17 +72,14 @@
 	var env *C.JNIEnv
 	C.AttachCurrentThread(id.jVM, &env, nil)
 	defer C.DetachCurrentThread(id.jVM)
-	util.GoRef(&context) // un-refed when the Java Context object is finalized.
+	jContext := newJavaContext(env, context)
 	contextSign := util.ClassSign("com.veyron2.security.Context")
 	publicIDSign := util.ClassSign("com.veyron2.security.PublicID")
-	cid := C.jmethodID(util.JMethodIDPtrOrDie(env, jContextImplClass, "<init>", util.FuncSign([]util.Sign{util.LongSign}, util.VoidSign)))
-	jContext := C.CallPublicIDNewContextObject(env, jContextImplClass, cid, C.jlong(util.PtrValue(&context)))
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, id.jPublicID), "authorize", util.FuncSign([]util.Sign{contextSign}, publicIDSign)))
-	jPublicID := C.CallPublicIDAuthorizeMethod(env, id.jPublicID, mid, jContext)
-	if err := util.JExceptionMsg(env); err != nil {
+	jPublicID, err := util.CallObjectMethod(env, id.jPublicID, "authorize", []util.Sign{contextSign}, publicIDSign, jContext)
+	if err != nil {
 		return nil, err
 	}
-	return newPublicID(env, jPublicID), nil
+	return newPublicID(env, C.jobject(jPublicID)), nil
 }
 
 func (id *publicID) ThirdPartyCaveats() []security.ServiceCaveat {
@@ -122,15 +87,12 @@
 	C.AttachCurrentThread(id.jVM, &env, nil)
 	defer C.DetachCurrentThread(id.jVM)
 	serviceCaveatSign := util.ClassSign("com.veyron2.security.ServiceCaveat")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, C.GetObjectClass(env, id.jPublicID), "thirdPartyCaveats", util.FuncSign(nil, util.ArraySign(serviceCaveatSign))))
-	jServiceCaveats := C.CallPublicIDThirdPartyCaveatsMethod(env, id.jPublicID, mid)
-	length := int(C.GetArrayLength(env, C.jarray(jServiceCaveats)))
-	sCaveats := make([]security.ServiceCaveat, length)
-	for i := 0; i < length; i++ {
-		jServiceCaveat := C.GetObjectArrayElement(env, jServiceCaveats, C.jsize(i))
+	jServiceCaveats := util.CallObjectArrayMethodOrCatch(env, id.jPublicID, "thirdPartyCaveats", nil, util.ArraySign(serviceCaveatSign))
+	sCaveats := make([]security.ServiceCaveat, len(jServiceCaveats))
+	for i, jcaveat := range jServiceCaveats {
 		sCaveats[i] = security.ServiceCaveat{
-			Service: security.PrincipalPattern(util.JStringField(env, jServiceCaveat, "service")),
-			Caveat:  newCaveat(env, jServiceCaveat),
+			Service: security.PrincipalPattern(util.JStringField(env, C.jobject(jcaveat), "service")),
+			Caveat:  newCaveat(env, C.jobject(jcaveat)),
 		}
 	}
 	return sCaveats
@@ -139,8 +101,7 @@
 func newPublicKey(env *C.JNIEnv, jPublicKey C.jobject) *ecdsa.PublicKey {
 	keySign := util.ClassSign("java.security.interfaces.ECPublicKey")
 	keyInfoSign := util.ClassSign("com.veyron.runtimes.google.security.PublicID$ECPublicKeyInfo")
-	mid := C.jmethodID(util.JMethodIDPtrOrDie(env, jPublicIDImplClass, "getKeyInfo", util.FuncSign([]util.Sign{keySign}, keyInfoSign)))
-	jKeyInfo := C.CallPublicIDGetKeyInfoMethod(env, jPublicIDImplClass, mid, jPublicKey)
+	jKeyInfo := C.jobject(util.CallStaticObjectMethodOrCatch(env, jPublicIDImplClass, "getKeyInfo", []util.Sign{keySign}, keyInfoSign, jPublicKey))
 	keyX := new(big.Int).SetBytes(util.JByteArrayField(env, jKeyInfo, "keyX"))
 	keyY := new(big.Int).SetBytes(util.JByteArrayField(env, jKeyInfo, "keyY"))
 	var curve elliptic.Curve