''' Java wrapper ============ With this module, you can create Python class that reflect a Java class, and use it directly in Python. Example with static method -------------------------- Java:: package org.test; public class Hardware { static int getDPI() { return metrics.densityDpi; } } Python:: class Hardware(JavaClass): __metaclass__ = MetaJavaClass __javaclass__ = 'org/test/Hardware' getDPI = JavaStaticMethod('()I') Hardware.getDPI() Example with instance method ---------------------------- Java:: package org.test; public class Action { public String getName() { return new String("Hello world") } } Python:: class Action(JavaClass): __metaclass__ = MetaJavaClass __javaclass__ = 'org/test/Action' getName = JavaMethod('()Ljava/lang/String;') action = Action() print action.getName() # will output Hello World Example with static/instance field ---------------------------------- Java:: package org.test; public class Test { public static String field1 = new String("hello"); public String field2; public Test() { this.field2 = new String("world"); } } Python:: class Test(JavaClass): __metaclass__ = MetaJavaClass __javaclass__ = 'org/test/Test' field1 = JavaStaticField('Ljava/lang/String;') field2 = JavaField('Ljava/lang/String;') # access directly to the static field print Test.field1 # create the instance, and access to the instance field test = Test() print test.field2 ''' __all__ = ('JavaObject', 'JavaClass', 'JavaMethod', 'JavaStaticMethod', 'JavaField', 'JavaStaticField', 'MetaJavaClass') from libc.stdlib cimport malloc, free include "jni.pxi" include "config.pxi" IF JNIUS_PLATFORM == "android": include "jnius_jvm_android.pxi" ELSE: include "jnius_jvm_desktop.pxi" cdef parse_definition(definition): # not a function, just a field if definition[0] != '(': return definition, None # it's a function! argdef, ret = definition[1:].split(')') args = [] while len(argdef): c = argdef[0] # read the array char prefix = '' if c == '[': prefix = c argdef = argdef[1:] c = argdef[0] # native type if c in 'ZBCSIJFD': args.append(prefix + c) argdef = argdef[1:] continue # java class if c == 'L': c, argdef = argdef.split(';', 1) args.append(prefix + c + ';') return ret, args cdef convert_jarray_to_python(JNIEnv *j_env, definition, jobject j_object): cdef jboolean iscopy cdef jboolean *j_booleans cdef jbyte *j_bytes cdef jchar *j_chars cdef jshort *j_shorts cdef jint *j_ints cdef jlong *j_longs cdef jfloat *j_floats cdef jdouble *j_doubles cdef object ret = None cdef jsize array_size cdef int i cdef jobject obj cdef char *c_str cdef bytes py_str cdef JavaObject ret_jobject cdef JavaClass ret_jc if j_object == NULL: return None array_size = j_env[0].GetArrayLength(j_env, j_object) r = definition[0] if r == 'Z': j_booleans = j_env[0].GetBooleanArrayElements( j_env, j_object, &iscopy) ret = [(True if j_booleans[i] else False) for i in range(array_size)] if iscopy: j_env[0].ReleaseBooleanArrayElements( j_env, j_object, j_booleans, 0) elif r == 'B': j_bytes = j_env[0].GetByteArrayElements( j_env, j_object, &iscopy) ret = [(j_bytes[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseByteArrayElements( j_env, j_object, j_bytes, 0) elif r == 'C': j_chars = j_env[0].GetCharArrayElements( j_env, j_object, &iscopy) ret = [(j_chars[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseCharArrayElements( j_env, j_object, j_chars, 0) elif r == 'S': j_shorts = j_env[0].GetShortArrayElements( j_env, j_object, &iscopy) ret = [(j_shorts[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseShortArrayElements( j_env, j_object, j_shorts, 0) elif r == 'I': j_ints = j_env[0].GetIntArrayElements( j_env, j_object, &iscopy) ret = [(j_ints[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseIntArrayElements( j_env, j_object, j_ints, 0) elif r == 'J': j_longs = j_env[0].GetLongArrayElements( j_env, j_object, &iscopy) ret = [(j_longs[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseLongArrayElements( j_env, j_object, j_longs, 0) elif r == 'F': j_floats = j_env[0].GetFloatArrayElements( j_env, j_object, &iscopy) ret = [(j_floats[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseFloatArrayElements( j_env, j_object, j_floats, 0) elif r == 'D': j_doubles = j_env[0].GetDoubleArrayElements( j_env, j_object, &iscopy) ret = [(j_doubles[i]) for i in range(array_size)] if iscopy: j_env[0].ReleaseDoubleArrayElements( j_env, j_object, j_doubles, 0) elif r == 'L': r = definition[1:-1] ret = [] if r == 'java/lang/String': for i in range(array_size): obj = j_env[0].GetObjectArrayElement( j_env, j_object, i) if obj == NULL: ret.append(None) continue c_str = j_env[0].GetStringUTFChars( j_env, obj, NULL) py_str = c_str j_env[0].ReleaseStringUTFChars( j_env, j_object, c_str) ret.append(py_str) j_env[0].DeleteLocalRef(j_env, obj) elif r in jclass_register: for i in range(array_size): obj = j_env[0].GetObjectArrayElement( j_env, j_object, i) ret_jc = jclass_register[r](noinstance=True) ret_jc.instanciate_from(obj) ret.append(ret_jc) j_env[0].DeleteLocalRef(j_env, obj) else: for i in range(array_size): obj = j_env[0].GetObjectArrayElement( j_env, j_object, i) if obj == NULL: ret.append(None) continue ret_jobject = JavaObject() ret_jobject.obj = obj ret.append(ret_jobject) else: raise JavaException('Invalid return definition for array') return ret cdef void release_args(JNIEnv *j_env, list definition_args, jvalue *j_args, args) except *: # do the conversion from a Python object to Java from a Java definition cdef JavaObject jo cdef JavaClass jc cdef int index for index, argtype in enumerate(definition_args): py_arg = args[index] if argtype[0] == 'L': if py_arg is None: j_args[index].l = NULL if isinstance(py_arg, basestring) and \ argtype in ('Ljava/lang/String;', 'Ljava/lang/Object;'): j_env[0].DeleteLocalRef(j_env, j_args[index].l) elif argtype[0] == '[': j_env[0].DeleteLocalRef(j_env, j_args[index].l) cdef void populate_args(JNIEnv *j_env, list definition_args, jvalue *j_args, args) except *: # do the conversion from a Python object to Java from a Java definition cdef JavaObject jo cdef JavaClass jc cdef int index for index, argtype in enumerate(definition_args): py_arg = args[index] if argtype == 'Z': j_args[index].z = py_arg elif argtype == 'B': j_args[index].b = py_arg elif argtype == 'C': j_args[index].c = ord(py_arg) elif argtype == 'S': j_args[index].s = py_arg elif argtype == 'I': j_args[index].i = py_arg elif argtype == 'J': j_args[index].j = py_arg elif argtype == 'F': j_args[index].f = py_arg elif argtype == 'D': j_args[index].d = py_arg elif argtype[0] == 'L': if py_arg is None: j_args[index].l = NULL elif isinstance(py_arg, basestring) and \ argtype in ('Ljava/lang/String;', 'Ljava/lang/Object;'): j_args[index].l = j_env[0].NewStringUTF( j_env, py_arg) elif isinstance(py_arg, JavaClass): jc = py_arg if argtype != 'Ljava/lang/Object;' and jc.__javaclass__ != argtype[1:-1]: raise JavaException('Invalid class argument, want ' '{0!r}, got {1!r}'.format( argtype[1:-1], jc.__javaclass__)) j_args[index].l = jc.j_self elif isinstance(py_arg, JavaObject): jo = py_arg j_args[index].l = jo.obj raise JavaException('JavaObject needed for argument ' '{0}'.format(index)) else: raise JavaException('Invalid python object for this ' 'argument. Want {0!r}, got {1!r}'.format( argtype[1:-1], py_arg)) elif argtype[0] == '[': if not isinstance(py_arg, list) and \ not isinstance(py_arg, tuple): raise JavaException('Expecting a python list/tuple, got ' '{0!r}'.format(py_arg)) j_args[index].l = convert_pyarray_to_java( j_env, argtype[1:], py_arg) cdef jobject convert_pyarray_to_java(JNIEnv *j_env, definition, pyarray): cdef jobject ret = NULL cdef int array_size = len(pyarray) cdef int i cdef jboolean j_boolean cdef jbyte j_byte cdef jchar j_char cdef jshort j_short cdef jint j_int cdef jlong j_long cdef jfloat j_float cdef jdouble j_double cdef jstring j_string cdef jclass j_class cdef JavaObject jo cdef JavaClass jc if definition == 'Z': ret = j_env[0].NewBooleanArray(j_env, array_size) for i in range(array_size): j_boolean = 1 if pyarray[i] else 0 j_env[0].SetBooleanArrayRegion(j_env, ret, i, 1, &j_boolean) elif definition == 'B': ret = j_env[0].NewByteArray(j_env, array_size) for i in range(array_size): j_byte = pyarray[i] j_env[0].SetByteArrayRegion(j_env, ret, i, 1, &j_byte) elif definition == 'C': ret = j_env[0].NewCharArray(j_env, array_size) for i in range(array_size): j_char = ord(pyarray[i]) j_env[0].SetCharArrayRegion(j_env, ret, i, 1, &j_char) elif definition == 'S': ret = j_env[0].NewShortArray(j_env, array_size) for i in range(array_size): j_short = pyarray[i] j_env[0].SetShortArrayRegion(j_env, ret, i, 1, &j_short) elif definition == 'I': ret = j_env[0].NewIntArray(j_env, array_size) for i in range(array_size): j_int = pyarray[i] j_env[0].SetIntArrayRegion(j_env, ret, i, 1, &j_int) elif definition == 'J': ret = j_env[0].NewLongArray(j_env, array_size) for i in range(array_size): j_long = pyarray[i] j_env[0].SetLongArrayRegion(j_env, ret, i, 1, &j_long) elif definition == 'F': ret = j_env[0].NewFloatArray(j_env, array_size) for i in range(array_size): j_float = pyarray[i] j_env[0].SetFloatArrayRegion(j_env, ret, i, 1, &j_float) elif definition == 'D': ret = j_env[0].NewDoubleArray(j_env, array_size) for i in range(array_size): j_double = pyarray[i] j_env[0].SetDoubleArrayRegion(j_env, ret, i, 1, &j_double) elif definition[0] == 'L': j_class = j_env[0].FindClass( j_env, definition[1:-1]) if j_class == NULL: raise JavaException('Cannot create array with a class not ' 'found {0!r}'.format(definition[1:-1])) ret = j_env[0].NewObjectArray( j_env, array_size, j_class, NULL) for i in range(array_size): arg = pyarray[i] if arg is None: j_env[0].SetObjectArrayElement( j_env, ret, i, NULL) elif isinstance(arg, basestring) and \ definition == 'Ljava/lang/String;': j_string = j_env[0].NewStringUTF( j_env, arg) j_env[0].SetObjectArrayElement( j_env, ret, i, j_string) elif isinstance(arg, JavaClass): jc = arg if jc.__javaclass__ != definition[1:-1]: raise JavaException('Invalid class argument, want ' '{0!r}, got {1!r}'.format( definition[1:-1], jc.__javaclass__)) j_env[0].SetObjectArrayElement( j_env, ret, i, jc.j_self) elif isinstance(arg, JavaObject): jo = arg j_env[0].SetObjectArrayElement( j_env, ret, i, jo.obj) else: raise JavaException('Invalid variable used for L array') else: raise JavaException('Invalid array definition') return ret cdef void check_exception(JNIEnv *j_env): cdef jthrowable exc = j_env[0].ExceptionOccurred(j_env) if exc: j_env[0].ExceptionDescribe(j_env) j_env[0].ExceptionClear(j_env) cdef bytes lookup_java_object_name(JNIEnv *j_env, jobject j_obj): from reflect import ensureclass, autoclass ensureclass('java.lang.Object') ensureclass('java.lang.Class') cdef JavaClass obj = autoclass('java.lang.Object')(noinstance=True) obj.instanciate_from(j_obj) cls = obj.getClass() name = cls.getName() ensureclass(name) return name.replace('.', '/') class JavaException(Exception): '''Can be a real java exception, or just an exception from the wrapper. ''' pass cdef class JavaObject(object): '''Can contain any Java object. Used to store instance, or whatever. ''' cdef jobject obj def __cinit__(self): self.obj = NULL cdef class JavaClassStorage: cdef JNIEnv *j_env cdef jclass j_cls def __cinit__(self): self.j_env = NULL self.j_cls = NULL cdef dict jclass_register = {} class MetaJavaClass(type): def __new__(meta, classname, bases, classDict): meta.resolve_class(classDict) tp = type.__new__(meta, classname, bases, classDict) jclass_register[classDict['__javaclass__']] = tp #print 'REGISTER', classDict['__javaclass__'], tp return tp @staticmethod def get_javaclass(name): return jclass_register.get(name) @classmethod def resolve_class(meta, classDict): # search the Java class, and bind to our object if not '__javaclass__' in classDict: raise JavaException('__javaclass__ definition missing') cdef JavaClassStorage jcs = JavaClassStorage() cdef str __javaclass__ = classDict['__javaclass__'] jcs.j_env = get_jnienv() if jcs.j_env == NULL: raise JavaException('Unable to get the Android JNI Environment') jcs.j_cls = jcs.j_env[0].FindClass(jcs.j_env, __javaclass__) if jcs.j_cls == NULL: raise JavaException('Unable to found the class' ' {0}'.format(__javaclass__)) classDict['__cls_storage'] = jcs # search all the static JavaMethod within our class, and resolve them cdef JavaMethod jm for name, value in classDict.iteritems(): if not isinstance(value, JavaMethod): continue jm = value if not jm.is_static: continue jm.resolve_static_method(jcs.j_env, jcs.j_cls, name) # search all the static JavaField within our class, and resolve them cdef JavaField jf for name, value in classDict.iteritems(): if not isinstance(value, JavaField): continue jf = value if not jf.is_static: continue jf.resolve_static_field(jcs.j_env, jcs.j_cls, name) cdef class JavaClass(object): '''Main class to do introspection. ''' cdef JNIEnv *j_env cdef jclass j_cls cdef jobject j_self def __cinit__(self, *args, **kwargs): self.j_env = NULL self.j_cls = NULL self.j_self = NULL def __dealloc__(self): if self.j_self: self.j_env[0].DeleteLocalRef(self.j_env, self.j_self); self.j_self = NULL def __init__(self, *args, **kwargs): super(JavaClass, self).__init__() # copy the current attribute in the storage to our class cdef JavaClassStorage jcs = self.__cls_storage self.j_env = jcs.j_env self.j_cls = jcs.j_cls if 'noinstance' not in kwargs: self.call_constructor(args) self.resolve_methods() self.resolve_fields() cdef void instanciate_from(self, jobject j_self): j_self = self.j_env[0].NewLocalRef(self.j_env, j_self) self.j_self = j_self self.resolve_methods() self.resolve_fields() cdef void call_constructor(self, args): # the goal is to found the class constructor, and call it with the # correct arguments. cdef jvalue *j_args = NULL cdef jmethodID constructor = NULL # get the constructor definition if exist definition = '()V' if hasattr(self, '__javaconstructor__'): definition = self.__javaconstructor__ self.definition = definition d_ret, d_args = parse_definition(definition) if len(args) != len(d_args): raise JavaException('Invalid call, number of argument' ' mismatch for constructor') try: # convert python arguments to java arguments if len(args): j_args = malloc(sizeof(jvalue) * len(d_args)) if j_args == NULL: raise MemoryError('Unable to allocate memory for java args') populate_args(self.j_env, d_args, j_args, args) # get the java constructor constructor = self.j_env[0].GetMethodID( self.j_env, self.j_cls, '', definition) if constructor == NULL: raise JavaException('Unable to found the constructor' ' for {0}'.format(self.__javaclass__)) # create the object self.j_self = self.j_env[0].NewObjectA(self.j_env, self.j_cls, constructor, j_args) if self.j_self == NULL: raise JavaException('Unable to instanciate {0}'.format( self.__javaclass__)) finally: if j_args != NULL: free(j_args) cdef void resolve_methods(self): # search all the JavaMethod within our class, and resolve them cdef JavaMethod jm for name, value in self.__class__.__dict__.iteritems(): if not isinstance(value, JavaMethod): continue jm = value if jm.is_static: continue jm.resolve_method(self, name) cdef void resolve_fields(self): # search all the JavaField within our class, and resolve them cdef JavaField jf for name, value in self.__class__.__dict__.iteritems(): if not isinstance(value, JavaField): continue jf = value if jf.is_static: continue jf.resolve_field(self, name) def __repr__(self): return '<{0} at 0x{1:x} jclass={2} jself={3}>'.format( self.__class__.__name__, id(self), self.__javaclass__, self.j_self) cdef class JavaField(object): cdef jfieldID j_field cdef JNIEnv *j_env cdef jclass j_cls cdef jobject j_self cdef bytes definition cdef object is_static def __cinit__(self, definition, **kwargs): self.j_field = NULL self.j_env = NULL self.j_cls = NULL self.j_self = NULL def __init__(self, definition, **kwargs): super(JavaField, self).__init__() self.definition = definition self.is_static = kwargs.get('static', False) cdef void resolve_field(self, JavaClass jc, bytes name): # called by JavaClass when we want to resolve the field name assert(self.is_static is False) self.j_env = jc.j_env self.j_cls = jc.j_cls self.j_self = jc.j_self self.j_field = self.j_env[0].GetFieldID( self.j_env, self.j_cls, name, self.definition) if self.j_field == NULL: raise JavaException('Unable to found the field' ' {0} in {1}'.format(name, jc.__javaclass__)) cdef void resolve_static_field(self, JNIEnv *j_env, jclass j_cls, bytes name): # called by JavaClass when we want to resolve the field name assert(self.is_static is True) self.j_env = j_env self.j_cls = j_cls self.j_field = self.j_env[0].GetStaticFieldID( self.j_env, self.j_cls, name, self.definition) if self.j_field == NULL: raise JavaException('Unable to found the field' ' {0}'.format(name)) def __get__(self, obj, objtype): if obj is None: return self.read_static_field() return self.read_field() cdef read_field(self): cdef jboolean j_boolean cdef jbyte j_byte cdef jchar j_char cdef jshort j_short cdef jint j_int cdef jlong j_long cdef jfloat j_float cdef jdouble j_double cdef jobject j_object cdef char *c_str cdef bytes py_str cdef object ret = None cdef JavaObject ret_jobject cdef JavaClass ret_jc # return type of the java method r = self.definition[0] # now call the java method if r == 'Z': j_boolean = self.j_env[0].GetBooleanField( self.j_env, self.j_self, self.j_field) ret = True if j_boolean else False elif r == 'B': j_byte = self.j_env[0].GetByteField( self.j_env, self.j_self, self.j_field) ret = j_byte elif r == 'C': j_char = self.j_env[0].GetCharField( self.j_env, self.j_self, self.j_field) ret = chr(j_char) elif r == 'S': j_short = self.j_env[0].GetShortField( self.j_env, self.j_self, self.j_field) ret = j_short elif r == 'I': j_int = self.j_env[0].GetIntField( self.j_env, self.j_self, self.j_field) ret = j_int elif r == 'J': j_long = self.j_env[0].GetLongField( self.j_env, self.j_self, self.j_field) ret = j_long elif r == 'F': j_float = self.j_env[0].GetFloatField( self.j_env, self.j_self, self.j_field) ret = j_float elif r == 'D': j_double = self.j_env[0].GetDoubleField( self.j_env, self.j_self, self.j_field) ret = j_double elif r == 'L': j_object = self.j_env[0].GetObjectField( self.j_env, self.j_self, self.j_field) if j_object == NULL: return None r = self.definition[1:-1] if r == 'java/lang/Object': r = lookup_java_object_name(self.j_env, j_object) if r == 'java/lang/String': c_str = self.j_env[0].GetStringUTFChars( self.j_env, j_object, NULL) py_str = c_str self.j_env[0].ReleaseStringUTFChars( self.j_env, j_object, c_str) ret = py_str elif r in jclass_register: ret_jc = jclass_register[r](noinstance=True) ret_jc.instanciate_from(j_object) ret = ret_jc else: ret_jobject = JavaObject() ret_jobject.obj = self.j_env[0].NewLocalRef(self.j_env, j_object) ret = ret_jobject self.j_env[0].DeleteLocalRef(self.j_env, j_object) elif r == '[': r = self.definition[1:] j_object = self.j_env[0].GetObjectField( self.j_env, self.j_self, self.j_field) ret = convert_jarray_to_python(self.j_env, r, j_object) self.j_env[0].DeleteLocalRef(self.j_env, j_object) else: raise Exception('Invalid field definition') check_exception(self.j_env) return ret cdef read_static_field(self): cdef jboolean j_boolean cdef jbyte j_byte cdef jchar j_char cdef jshort j_short cdef jint j_int cdef jlong j_long cdef jfloat j_float cdef jdouble j_double cdef jobject j_object cdef char *c_str cdef bytes py_str cdef object ret = None cdef JavaObject ret_jobject cdef JavaClass ret_jc # return type of the java method r = self.definition[0] # now call the java method if r == 'Z': j_boolean = self.j_env[0].GetStaticBooleanField( self.j_env, self.j_self, self.j_field) ret = True if j_boolean else False elif r == 'B': j_byte = self.j_env[0].GetStaticByteField( self.j_env, self.j_self, self.j_field) ret = j_byte elif r == 'C': j_char = self.j_env[0].GetStaticCharField( self.j_env, self.j_self, self.j_field) ret = chr(j_char) elif r == 'S': j_short = self.j_env[0].GetStaticShortField( self.j_env, self.j_self, self.j_field) ret = j_short elif r == 'I': j_int = self.j_env[0].GetStaticIntField( self.j_env, self.j_self, self.j_field) ret = j_int elif r == 'J': j_long = self.j_env[0].GetStaticLongField( self.j_env, self.j_self, self.j_field) ret = j_long elif r == 'F': j_float = self.j_env[0].GetStaticFloatField( self.j_env, self.j_self, self.j_field) ret = j_float elif r == 'D': j_double = self.j_env[0].GetStaticDoubleField( self.j_env, self.j_self, self.j_field) ret = j_double elif r == 'L': j_object = self.j_env[0].GetStaticObjectField( self.j_env, self.j_self, self.j_field) if j_object == NULL: return None r = self.definition[1:-1] if r == 'java/lang/Object': r = lookup_java_object_name(self.j_env, j_object) if r == 'java/lang/String': c_str = self.j_env[0].GetStringUTFChars( self.j_env, j_object, NULL) py_str = c_str self.j_env[0].ReleaseStringUTFChars( self.j_env, j_object, c_str) ret = py_str elif r in jclass_register: ret_jc = jclass_register[r](noinstance=True) ret_jc.instanciate_from(j_object) ret = ret_jc else: ret_jobject = JavaObject() ret_jobject.obj = self.j_env[0].NewLocalRef(self.j_env, j_object) ret = ret_jobject self.j_env[0].DeleteLocalRef(self.j_env, j_object) elif r == '[': r = self.definition[1:] j_object = self.j_env[0].GetStaticObjectField( self.j_env, self.j_self, self.j_field) ret = convert_jarray_to_python(self.j_env, r, j_object) self.j_env[0].DeleteLocalRef(self.j_env, j_object) else: raise Exception('Invalid field definition') check_exception(self.j_env) return ret cdef class JavaMethod(object): '''Used to resolve a Java method, and do the call ''' cdef jmethodID j_method cdef JNIEnv *j_env cdef jclass j_cls cdef jobject j_self cdef bytes name cdef bytes definition cdef object is_static cdef object definition_return cdef object definition_args def __cinit__(self, definition, **kwargs): self.j_method = NULL self.j_env = NULL self.j_cls = NULL self.j_self = NULL def __init__(self, definition, **kwargs): super(JavaMethod, self).__init__() self.definition = definition self.definition_return, self.definition_args = \ parse_definition(definition) self.is_static = kwargs.get('static', False) cdef void resolve_method(self, JavaClass jc, bytes name): # called by JavaClass when we want to resolve the method name assert(self.is_static is False) self.name = name self.j_env = jc.j_env self.j_cls = jc.j_cls self.j_self = jc.j_self self.j_method = self.j_env[0].GetMethodID( self.j_env, self.j_cls, name, self.definition) if self.j_method == NULL: raise JavaException('Unable to found the method' ' {0} in {1}'.format(name, jc.__javaclass__)) cdef void resolve_static_method(self, JNIEnv *j_env, jclass j_cls, bytes name): # called by JavaClass when we want to resolve the method name assert(self.is_static is True) self.j_env = j_env self.j_cls = j_cls self.j_method = self.j_env[0].GetStaticMethodID( self.j_env, self.j_cls, name, self.definition) if self.j_method == NULL: raise JavaException('Unable to found the method' ' {0}'.format(name)) def __get__(self, obj, objtype): if obj is None: return self # XXX FIXME we MUST not change our own j_self, but return an "bounded" # method here, as python does! cdef JavaClass jc = obj self.j_self = jc.j_self return self def __call__(self, *args): # argument array to pass to the method cdef jvalue *j_args = NULL cdef list d_args = self.definition_args if len(args) != len(d_args): raise JavaException('Invalid call, number of argument mismatch') if not self.is_static and self.j_env == NULL: raise JavaException('Cannot call instance method on a un-instanciated class') try: # convert python argument if necessary if len(args): j_args = malloc(sizeof(jvalue) * len(d_args)) if j_args == NULL: raise MemoryError('Unable to allocate memory for java args') populate_args(self.j_env, self.definition_args, j_args, args) try: # do the call if self.is_static: return self.call_staticmethod(j_args) return self.call_method(j_args) finally: release_args(self.j_env, self.definition_args, j_args, args) finally: if j_args != NULL: free(j_args) cdef call_method(self, jvalue *j_args): cdef jboolean j_boolean cdef jbyte j_byte cdef jchar j_char cdef jshort j_short cdef jint j_int cdef jlong j_long cdef jfloat j_float cdef jdouble j_double cdef jobject j_object cdef char *c_str cdef bytes py_str cdef object ret = None cdef JavaObject ret_jobject cdef JavaClass ret_jc # return type of the java method r = self.definition_return[0] # now call the java method if r == 'V': self.j_env[0].CallVoidMethodA( self.j_env, self.j_self, self.j_method, j_args) elif r == 'Z': j_boolean = self.j_env[0].CallBooleanMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = True if j_boolean else False elif r == 'B': j_byte = self.j_env[0].CallByteMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_byte elif r == 'C': j_char = self.j_env[0].CallCharMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = chr(j_char) elif r == 'S': j_short = self.j_env[0].CallShortMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_short elif r == 'I': j_int = self.j_env[0].CallIntMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_int elif r == 'J': j_long = self.j_env[0].CallLongMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_long elif r == 'F': j_float = self.j_env[0].CallFloatMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_float elif r == 'D': j_double = self.j_env[0].CallDoubleMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = j_double elif r == 'L': j_object = self.j_env[0].CallObjectMethodA( self.j_env, self.j_self, self.j_method, j_args) check_exception(self.j_env) if j_object == NULL: return None r = self.definition_return[1:-1] if r == 'java/lang/Object': r = lookup_java_object_name(self.j_env, j_object) if r == 'java/lang/String': c_str = self.j_env[0].GetStringUTFChars( self.j_env, j_object, NULL) py_str = c_str self.j_env[0].ReleaseStringUTFChars( self.j_env, j_object, c_str) ret = py_str elif r in jclass_register: ret_jc = jclass_register[r](noinstance=True) ret_jc.instanciate_from(j_object) ret = ret_jc else: ret_jobject = JavaObject() ret_jobject.obj = self.j_env[0].NewLocalRef(self.j_env, j_object) ret = ret_jobject self.j_env[0].DeleteLocalRef(self.j_env, j_object) elif r == '[': r = self.definition_return[1:] j_object = self.j_env[0].CallObjectMethodA( self.j_env, self.j_self, self.j_method, j_args) ret = convert_jarray_to_python(self.j_env, r, j_object) self.j_env[0].DeleteLocalRef(self.j_env, j_object) else: raise Exception('Invalid return definition?') check_exception(self.j_env) return ret cdef call_staticmethod(self, jvalue *j_args): cdef jboolean j_boolean cdef jbyte j_byte cdef jchar j_char cdef jshort j_short cdef jint j_int cdef jlong j_long cdef jfloat j_float cdef jdouble j_double cdef jobject j_object cdef char *c_str cdef bytes py_str cdef object ret = None cdef JavaObject ret_jobject cdef JavaClass ret_jc # return type of the java method r = self.definition_return[0] # now call the java method if r == 'V': self.j_env[0].CallStaticVoidMethodA( self.j_env, self.j_cls, self.j_method, j_args) elif r == 'Z': j_boolean = self.j_env[0].CallStaticBooleanMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = True if j_boolean else False elif r == 'B': j_byte = self.j_env[0].CallStaticByteMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_byte elif r == 'C': j_char = self.j_env[0].CallStaticCharMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = chr(j_char) elif r == 'S': j_short = self.j_env[0].CallStaticShortMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_short elif r == 'I': j_int = self.j_env[0].CallStaticIntMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_int elif r == 'J': j_long = self.j_env[0].CallStaticLongMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_long elif r == 'F': j_float = self.j_env[0].CallStaticFloatMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_float elif r == 'D': j_double = self.j_env[0].CallStaticDoubleMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = j_double elif r == 'L': # accept only string for the moment j_object = self.j_env[0].CallStaticObjectMethodA( self.j_env, self.j_cls, self.j_method, j_args) r = self.definition_return[1:-1] if r == 'java/lang/Object': r = lookup_java_object_name(self.j_env, j_object) if r == 'java/lang/String': c_str = self.j_env[0].GetStringUTFChars( self.j_env, j_object, NULL) py_str = c_str self.j_env[0].ReleaseStringUTFChars( self.j_env, j_object, c_str) ret = py_str elif r in jclass_register: ret_jc = jclass_register[r](noinstance=True) ret_jc.instanciate_from(j_object) ret = ret_jc else: ret_jobject = JavaObject() ret_jobject.obj = self.j_env[0].NewLocalRef(self.j_env, j_object) ret = ret_jobject self.j_env[0].DeleteLocalRef(self.j_env, j_object) elif r == '[': r = self.definition_return[1:] j_object = self.j_env[0].CallStaticObjectMethodA( self.j_env, self.j_cls, self.j_method, j_args) ret = convert_jarray_to_python(self.j_env, r, j_object) self.j_env[0].DeleteLocalRef(self.j_env, j_object) else: raise Exception('Invalid return definition?') check_exception(self.j_env) return ret class JavaStaticMethod(JavaMethod): def __init__(self, definition, **kwargs): kwargs['static'] = True super(JavaStaticMethod, self).__init__(definition, **kwargs) class JavaStaticField(JavaField): def __init__(self, definition, **kwargs): kwargs['static'] = True super(JavaStaticField, self).__init__(definition, **kwargs)