diff --git a/jnius/jnius_env.pxi b/jnius/jnius_env.pxi index ed49fa9..9c26061 100644 --- a/jnius/jnius_env.pxi +++ b/jnius/jnius_env.pxi @@ -11,17 +11,22 @@ cdef JNIEnv *get_jnienv(): env_stack = 0 return env_current -cdef void push_jnienv(JNIEnv *env): +cdef void push_jnienv(JNIEnv *env) nogil: global env_stacks, env_stack, env_current if env_stack == 255: - raise Exception('Jnius: cannot push JNI env, too many entries') + with gil: + print('ERROR: Jnius cannot push JNI env, too many entries') + return env_stack += 1 env_stacks[env_stack] = env_current = env -cdef void pop_jnienv(): - global env_stacks, env_stack +cdef void pop_jnienv() nogil: + global env_stacks, env_stack, env_current if env_stack == 0: - raise Exception('Jnius: cannot pop JNI env, already at 0') + with gil: + print('ERROR: Jnius cannot pop JNI env, already at 0') + return env_stacks[env_stack] = NULL env_stack -= 1 env_current = env_stacks[env_stack] + diff --git a/jnius/jnius_proxy.pxi b/jnius/jnius_proxy.pxi index 62bc931..b8976b4 100644 --- a/jnius/jnius_proxy.pxi +++ b/jnius/jnius_proxy.pxi @@ -72,8 +72,9 @@ cdef class PythonJavaClass(object): return py_method(*args) -cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject +cdef jobject py_invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject j_method, jobjectArray args) with gil: + from .reflect import get_signature, Method cdef jfieldID ptrField cdef jlong jptr @@ -82,72 +83,79 @@ cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject cdef LocalRef ref cdef jobject j_arg + # get the python object + ptrField = j_env[0].GetFieldID(j_env, + j_env[0].GetObjectClass(j_env, j_this), "ptr", "J") + jptr = j_env[0].GetLongField(j_env, j_this, ptrField) + py_obj = jptr + + # extract the method information + method = Method(noinstance=True) + ref = create_local_ref(j_env, j_method) + method.instanciate_from(create_local_ref(j_env, j_method)) + ret_signature = get_signature(method.getReturnType()) + args_signature = [get_signature(x) for x in method.getParameterTypes()] + + # convert java argument to python object + # native java type are given with java.lang.*, even if the signature say + # it's a native type. + py_args = [] + convert_signature = { + 'Z': 'Ljava/lang/Boolean;', + 'B': 'Ljava/lang/Byte;', + 'C': 'Ljava/lang/Character;', + 'S': 'Ljava/lang/Short;', + 'I': 'Ljava/lang/Integer;', + 'J': 'Ljava/lang/Long;', + 'F': 'Ljava/lang/Float;', + 'D': 'Ljava/lang/Double;'} + + for index, arg_signature in enumerate(args_signature): + arg_signature = convert_signature.get(arg_signature, arg_signature) + j_arg = j_env[0].GetObjectArrayElement(j_env, args, index) + py_arg = convert_jobject_to_python(j_env, arg_signature, j_arg) + py_args.append(py_arg) + + # really invoke the python method + name = method.getName() + ret = py_obj.invoke(method, *py_args) + + # convert back to the return type + # use the populate_args(), but in the reverse way :) + t = ret_signature[:1] + + # did python returned a "native" type ? + jtype = None + + if ret_signature == 'Ljava/lang/Object;': + # generic object, try to manually convert it + tp = type(ret) + if tp == int: + jtype = 'J' + elif tp == float: + jtype = 'D' + elif tp == bool: + jtype = 'Z' + elif len(ret_signature) == 1: + jtype = ret_signature + try: - push_jnienv(j_env) + return convert_python_to_jobject(j_env, jtype or ret_signature, ret) + except Exception as e: + traceback.print_exc(e) - # get the python object - ptrField = j_env[0].GetFieldID(j_env, - j_env[0].GetObjectClass(j_env, j_this), "ptr", "J") - jptr = j_env[0].GetLongField(j_env, j_this, ptrField) - py_obj = jptr - - # extract the method information - method = Method(noinstance=True) - ref = create_local_ref(j_env, j_method) - method.instanciate_from(create_local_ref(j_env, j_method)) - ret_signature = get_signature(method.getReturnType()) - args_signature = [get_signature(x) for x in method.getParameterTypes()] - - # convert java argument to python object - # native java type are given with java.lang.*, even if the signature say - # it's a native type. - py_args = [] - convert_signature = { - 'Z': 'Ljava/lang/Boolean;', - 'B': 'Ljava/lang/Byte;', - 'C': 'Ljava/lang/Character;', - 'S': 'Ljava/lang/Short;', - 'I': 'Ljava/lang/Integer;', - 'J': 'Ljava/lang/Long;', - 'F': 'Ljava/lang/Float;', - 'D': 'Ljava/lang/Double;'} - - for index, arg_signature in enumerate(args_signature): - arg_signature = convert_signature.get(arg_signature, arg_signature) - j_arg = j_env[0].GetObjectArrayElement(j_env, args, index) - py_arg = convert_jobject_to_python(j_env, arg_signature, j_arg) - py_args.append(py_arg) - - # really invoke the python method - name = method.getName() - ret = py_obj.invoke(method, *py_args) - - # convert back to the return type - # use the populate_args(), but in the reverse way :) - t = ret_signature[:1] - - # did python returned a "native" type ? - jtype = None - - if ret_signature == 'Ljava/lang/Object;': - # generic object, try to manually convert it - tp = type(ret) - if tp == int: - jtype = 'J' - elif tp == float: - jtype = 'D' - elif tp == bool: - jtype = 'Z' - elif len(ret_signature) == 1: - jtype = ret_signature +cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject + j_method, jobjectArray args) nogil: + cdef jobject ret = NULL + push_jnienv(j_env) + with gil: try: - return convert_python_to_jobject(j_env, jtype or ret_signature, ret) + ret = py_invoke0(j_env, j_this, j_proxy, j_method, args) except Exception as e: traceback.print_exc(e) - - finally: - pop_jnienv() + pop_jnienv() + return ret # now we need to create a proxy and pass it an invocation handler