mirror of https://github.com/kivy/pyjnius.git
cleanup proxy code
This commit is contained in:
parent
5fa7030778
commit
2a95adc674
|
@ -87,9 +87,11 @@ Python::
|
|||
|
||||
__all__ = ('JavaObject', 'JavaClass', 'JavaMethod', 'JavaField',
|
||||
'MetaJavaClass', 'JavaException', 'cast', 'find_javaclass',
|
||||
'PythonJavaClass', 'java_implementation')
|
||||
'PythonJavaClass', 'java_method')
|
||||
|
||||
from libc.stdlib cimport malloc, free
|
||||
from functools import partial
|
||||
import traceback
|
||||
|
||||
include "jni.pxi"
|
||||
include "config.pxi"
|
||||
|
@ -105,3 +107,5 @@ include "jnius_localref.pxi"
|
|||
|
||||
include "jnius_export_func.pxi"
|
||||
include "jnius_export_class.pxi"
|
||||
|
||||
include "jnius_proxy.pxi"
|
||||
|
|
|
@ -11,7 +11,7 @@ def cast(destclass, obj):
|
|||
return jc
|
||||
|
||||
def find_javaclass(bytes name):
|
||||
from reflect import Class
|
||||
from .reflect import Class
|
||||
cdef JavaClass cls
|
||||
cdef jclass jc
|
||||
cdef JNIEnv *j_env = get_jnienv()
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
class java_method(object):
|
||||
def __init__(self, signature, name=None):
|
||||
super(java_method, self).__init__()
|
||||
self.signature = signature
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, instancetype):
|
||||
return partial(self.__call__, instance)
|
||||
|
||||
def __call__(self, f):
|
||||
f.__javasignature__ = self.signature
|
||||
f.__javaname__ = self.name
|
||||
return f
|
||||
|
||||
|
||||
cdef class PythonJavaClass(object):
|
||||
'''
|
||||
Base class to create a java class from python
|
||||
'''
|
||||
cdef JNIEnv *j_env
|
||||
cdef jclass j_cls
|
||||
cdef public object j_self
|
||||
|
||||
def __cinit__(self, *args):
|
||||
self.j_env = get_jnienv()
|
||||
self.j_cls = NULL
|
||||
self.j_self = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.j_self = create_proxy_instance(self.j_env, self,
|
||||
self.__javainterfaces__)
|
||||
|
||||
# discover all the java method implemented
|
||||
self.__javamethods__ = {}
|
||||
for x in dir(self):
|
||||
attr = getattr(self, x)
|
||||
if not callable(attr):
|
||||
continue
|
||||
if not hasattr(attr, '__javasignature__'):
|
||||
continue
|
||||
signature = parse_definition(attr.__javasignature__)
|
||||
self.__javamethods__[(attr.__javaname__ or x, signature)] = attr
|
||||
|
||||
def invoke(self, method, *args):
|
||||
try:
|
||||
ret = self._invoke(method, *args)
|
||||
return ret
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
return None
|
||||
|
||||
def _invoke(self, method, *args):
|
||||
from .reflect import get_signature
|
||||
# search the java method
|
||||
|
||||
ret_signature = get_signature(method.getReturnType())
|
||||
args_signature = tuple([get_signature(x) for x in method.getParameterTypes()])
|
||||
method_name = method.getName()
|
||||
|
||||
key = (method_name, (ret_signature, args_signature))
|
||||
|
||||
py_method = self.__javamethods__.get(key, None)
|
||||
if not py_method:
|
||||
print(''.join(
|
||||
'\n===== Python/java method missing ======',
|
||||
'\nPython class:', self,
|
||||
'\nJava method name:', method_name,
|
||||
'\nSignature: ({}){}'.format(''.join(args_signature), ret_signature),
|
||||
'\n=======================================\n'))
|
||||
raise NotImplemented('The method {} is not implemented'.format(key))
|
||||
|
||||
return py_method(*args)
|
||||
|
||||
cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
j_method, jobjectArray args) except *:
|
||||
from .reflect import get_signature, Method
|
||||
|
||||
# get the python object
|
||||
cdef jfieldID ptrField = j_env[0].GetFieldID(j_env,
|
||||
j_env[0].GetObjectClass(j_env, j_this), "ptr", "J")
|
||||
cdef jlong jptr = j_env[0].GetLongField(j_env, j_this, ptrField)
|
||||
cdef object py_obj = <object>jptr
|
||||
|
||||
# extract the method information
|
||||
cdef JavaClass method = Method(noinstance=True)
|
||||
cdef LocalRef 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.
|
||||
cdef jobject j_arg
|
||||
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:
|
||||
return convert_python_to_jobject(j_env, jtype or ret_signature, ret)
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
|
||||
|
||||
# now we need to create a proxy and pass it an invocation handler
|
||||
cdef create_proxy_instance(JNIEnv *j_env, py_obj, j_interfaces):
|
||||
from .reflect import autoclass
|
||||
Proxy = autoclass('java.lang.reflect.Proxy')
|
||||
NativeInvocationHandler = autoclass('jnius.NativeInvocationHandler')
|
||||
ClassLoader = autoclass('java.lang.ClassLoader')
|
||||
|
||||
# convert strings to Class
|
||||
j_interfaces = [find_javaclass(x) for x in j_interfaces]
|
||||
|
||||
cdef JavaClass nih = NativeInvocationHandler(<long><void *>py_obj)
|
||||
cdef JNINativeMethod invoke_methods[1]
|
||||
invoke_methods[0].name = 'invoke0'
|
||||
invoke_methods[0].signature = '(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;'
|
||||
invoke_methods[0].fnPtr = <void *>&invoke0
|
||||
j_env[0].RegisterNatives(j_env, nih.j_cls, <JNINativeMethod *>invoke_methods, 1)
|
||||
|
||||
# create the proxy and pass it the invocation handler
|
||||
cdef JavaClass j_obj = Proxy.newProxyInstance(
|
||||
ClassLoader.getSystemClassLoader(), j_interfaces, nih)
|
||||
|
||||
return j_obj
|
|
@ -217,175 +217,3 @@ cdef int calculate_score(sign_args, args, is_varargs=False) except *:
|
|||
# a method with a better signature so we don't
|
||||
# change this method score
|
||||
return score
|
||||
|
||||
|
||||
import functools
|
||||
import traceback
|
||||
class java_implementation(object):
|
||||
def __init__(self, signature, name=None):
|
||||
super(java_implementation, self).__init__()
|
||||
self.signature = signature
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, instancetype):
|
||||
return functools.partial(self.__call__, instance)
|
||||
|
||||
def __call__(self, f):
|
||||
f.__javasignature__ = self.signature
|
||||
f.__javaname__ = self.name
|
||||
return f
|
||||
|
||||
cdef class PythonJavaClass(object):
|
||||
'''
|
||||
base class to create a java class from python
|
||||
'''
|
||||
cdef JNIEnv *j_env
|
||||
cdef jclass j_cls
|
||||
cdef public object j_self
|
||||
|
||||
def __cinit__(self, *args):
|
||||
self.j_env = get_jnienv()
|
||||
self.j_cls = NULL
|
||||
self.j_self = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.j_self = create_proxy_instance(self.j_env, self,
|
||||
self.__javainterfaces__)
|
||||
|
||||
# discover all the java method implementated
|
||||
self.__javamethods__ = {}
|
||||
for x in dir(self):
|
||||
attr = getattr(self, x)
|
||||
if not callable(attr):
|
||||
continue
|
||||
if not hasattr(attr, '__javasignature__'):
|
||||
continue
|
||||
signature = parse_definition(attr.__javasignature__)
|
||||
self.__javamethods__[(attr.__javaname__ or x, signature)] = attr
|
||||
|
||||
def invoke(self, method, *args):
|
||||
try:
|
||||
ret = self._invoke(method, *args)
|
||||
return ret
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
return None
|
||||
|
||||
def _invoke(self, method, *args):
|
||||
from .reflect import get_signature
|
||||
# search the java method
|
||||
|
||||
ret_signature = get_signature(method.getReturnType())
|
||||
args_signature = tuple([get_signature(x) for x in method.getParameterTypes()])
|
||||
method_name = method.getName()
|
||||
|
||||
key = (method_name, (ret_signature, args_signature))
|
||||
|
||||
py_method = self.__javamethods__.get(key, None)
|
||||
if not py_method:
|
||||
print(''.join(
|
||||
'\n===== Python/java method missing ======',
|
||||
'\nPython class:', self,
|
||||
'\nJava method name:', method_name,
|
||||
'\nSignature: ({}){}'.format(''.join(args_signature), ret_signature),
|
||||
'\n=======================================\n'))
|
||||
raise NotImplemented('The method {} is not implemented'.format(key))
|
||||
|
||||
return py_method(*args)
|
||||
|
||||
cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
j_method, jobjectArray args) except *:
|
||||
from .reflect import get_signature
|
||||
|
||||
# get the python object
|
||||
cdef jfieldID ptrField = j_env[0].GetFieldID(j_env,
|
||||
j_env[0].GetObjectClass(j_env, j_this), "ptr", "J")
|
||||
cdef jlong jptr = j_env[0].GetLongField(j_env, j_this, ptrField)
|
||||
cdef object py_obj = <object>jptr
|
||||
|
||||
# extract the method information
|
||||
from .reflect import Method
|
||||
cdef JavaClass method = Method(noinstance=True)
|
||||
cdef LocalRef 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.
|
||||
cdef jobject j_arg
|
||||
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:
|
||||
return convert_python_to_jobject(j_env, jtype or ret_signature, ret)
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
|
||||
|
||||
# now we need to create a proxy and pass it an invocation handler
|
||||
cdef create_proxy_instance(JNIEnv *j_env, py_obj, j_interfaces):
|
||||
from .reflect import autoclass
|
||||
Proxy = autoclass('java.lang.reflect.Proxy')
|
||||
NativeInvocationHandler = autoclass('jnius.NativeInvocationHandler')
|
||||
ClassLoader = autoclass('java.lang.ClassLoader')
|
||||
|
||||
# convert strings to Class
|
||||
j_interfaces = [find_javaclass(x) for x in j_interfaces]
|
||||
|
||||
cdef JavaClass nih = NativeInvocationHandler(<long><void *>py_obj)
|
||||
cdef JNINativeMethod invoke_methods[1]
|
||||
invoke_methods[0].name = 'invoke0'
|
||||
invoke_methods[0].signature = '(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;'
|
||||
invoke_methods[0].fnPtr = <void *>&invoke0
|
||||
j_env[0].RegisterNatives(j_env, nih.j_cls, <JNINativeMethod *>invoke_methods, 1)
|
||||
|
||||
cdef JavaClass j_obj = Proxy.newProxyInstance(
|
||||
ClassLoader.getSystemClassLoader(), j_interfaces, nih)
|
||||
|
||||
#for name, definition, method in py_obj.j_methods:
|
||||
# nw = GenericNativeWrapper(j_env, name, definition, method)
|
||||
# j_env.RegisterNatives(j_env[0], cls, nw.nm, 1)
|
||||
|
||||
# adds it to the invocationhandler
|
||||
|
||||
# create the proxy and pass it the invocation handler
|
||||
return j_obj
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from jnius import autoclass, java_implementation, PythonJavaClass, cast
|
||||
from jnius import autoclass, java_method, PythonJavaClass, cast
|
||||
|
||||
print '1: declare a TestImplem that implement Collection'
|
||||
|
||||
|
@ -13,39 +13,39 @@ class TestImplemIterator(PythonJavaClass):
|
|||
self.collection = collection
|
||||
self.index = index
|
||||
|
||||
@java_implementation('()Z')
|
||||
@java_method('()Z')
|
||||
def hasNext(self):
|
||||
return self.index < len(self.collection.data) - 1
|
||||
|
||||
@java_implementation('()Ljava/lang/Object;')
|
||||
@java_method('()Ljava/lang/Object;')
|
||||
def next(self):
|
||||
obj = self.collection.data[self.index]
|
||||
self.index += 1
|
||||
return obj
|
||||
|
||||
@java_implementation('()Z')
|
||||
@java_method('()Z')
|
||||
def hasPrevious(self):
|
||||
return self.index >= 0
|
||||
|
||||
@java_implementation('()Ljava/lang/Object;')
|
||||
@java_method('()Ljava/lang/Object;')
|
||||
def previous(self):
|
||||
self.index -= 1
|
||||
obj = self.collection.data[self.index]
|
||||
return obj
|
||||
|
||||
@java_implementation('()I')
|
||||
@java_method('()I')
|
||||
def previousIndex(self):
|
||||
return self.index - 1
|
||||
|
||||
@java_implementation('()Ljava/lang/String;')
|
||||
@java_method('()Ljava/lang/String;')
|
||||
def toString(self):
|
||||
return repr(self)
|
||||
|
||||
@java_implementation('(I)Ljava/lang/Object;')
|
||||
@java_method('(I)Ljava/lang/Object;')
|
||||
def get(self, index):
|
||||
return self.collection.data[index - 1]
|
||||
|
||||
@java_implementation('(Ljava/lang/Object;)V')
|
||||
@java_method('(Ljava/lang/Object;)V')
|
||||
def set(self, obj):
|
||||
self.collection.data[self.index - 1] = obj
|
||||
|
||||
|
@ -57,39 +57,39 @@ class TestImplem(PythonJavaClass):
|
|||
super(TestImplem, self).__init__(*args)
|
||||
self.data = list(args)
|
||||
|
||||
@java_implementation('()Ljava/util/Iterator;')
|
||||
@java_method('()Ljava/util/Iterator;')
|
||||
def iterator(self):
|
||||
it = TestImplemIterator(self)
|
||||
return it
|
||||
|
||||
@java_implementation('()Ljava/lang/String;')
|
||||
@java_method('()Ljava/lang/String;')
|
||||
def toString(self):
|
||||
return repr(self)
|
||||
|
||||
@java_implementation('()I')
|
||||
@java_method('()I')
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
|
||||
@java_implementation('(I)Ljava/lang/Object;')
|
||||
@java_method('(I)Ljava/lang/Object;')
|
||||
def get(self, index):
|
||||
return self.data[index]
|
||||
|
||||
@java_implementation('(ILjava/lang/Object;)Ljava/lang/Object;')
|
||||
@java_method('(ILjava/lang/Object;)Ljava/lang/Object;')
|
||||
def set(self, index, obj):
|
||||
old_object = self.data[index]
|
||||
self.data[index] = obj
|
||||
return old_object
|
||||
|
||||
@java_implementation('()[Ljava/lang/Object;')
|
||||
@java_method('()[Ljava/lang/Object;')
|
||||
def toArray(self):
|
||||
return self.data
|
||||
|
||||
@java_implementation('()Ljava/util/ListIterator;')
|
||||
@java_method('()Ljava/util/ListIterator;')
|
||||
def listIterator(self):
|
||||
it = TestImplemIterator(self)
|
||||
return it
|
||||
|
||||
@java_implementation('(I)Ljava/util/ListIterator;',
|
||||
@java_method('(I)Ljava/util/ListIterator;',
|
||||
name='ListIterator')
|
||||
def listIteratorI(self, index):
|
||||
it = TestImplemIterator(self, index)
|
||||
|
@ -138,5 +138,5 @@ print 'Order of data after shuffle()', a.data
|
|||
# XXX We have issues for methosd with multiple signature
|
||||
print '-> Collections.max(a)'
|
||||
print Collections.max(a2)
|
||||
print '-> Collections.shuffle(a)'
|
||||
print Collections.shuffle(a2)
|
||||
#print '-> Collections.shuffle(a)'
|
||||
#print Collections.shuffle(a2)
|
||||
|
|
Loading…
Reference in New Issue