// called internally to make new PyJObject instances PyObject* pyjobject_new(JNIEnv *env, jobject obj) { PyJObject *pyjob; jclass objClz; int jtype; if (!subtypes_initialized) { pyjobject_init_subtypes(); } if (!obj) { PyErr_Format(PyExc_RuntimeError, "Invalid object."); return NULL; } objClz = (*env)->GetObjectClass(env, obj); /* * There exist situations where a Java method signature has a return * type of Object but actually returns a Class or array. Also if you * call Jep.set(String, Object[]) it should be treated as an array, not * an object. Hence this check here to build the optimal jep type in * the interpreter regardless of signature. */ jtype = get_jtype(env, objClz); if (jtype == JARRAY_ID) { return pyjarray_new(env, obj); } else if (jtype == JCLASS_ID) { return pyjobject_new_class(env, obj); } else { #if JEP_NUMPY_ENABLED /* * check for jep/NDArray and autoconvert to numpy.ndarray instead of * pyjobject */ if (jndarray_check(env, obj)) { return convert_jndarray_pyndarray(env, obj); } if (PyErr_Occurred()) { return NULL; } #endif // check for some of our extensions to pyjobject if ((*env)->IsInstanceOf(env, obj, JITERABLE_TYPE)) { if ((*env)->IsInstanceOf(env, obj, JCOLLECTION_TYPE)) { if ((*env)->IsInstanceOf(env, obj, JLIST_TYPE)) { pyjob = (PyJObject*) pyjlist_new(); } else { // a Collection we have less support for pyjob = (PyJObject*) pyjcollection_new(); } } else { // an Iterable we have less support for pyjob = (PyJObject*) pyjiterable_new(); } } else if ((*env)->IsInstanceOf(env, obj, JMAP_TYPE)) { pyjob = (PyJObject*) pyjmap_new(); } else if ((*env)->IsInstanceOf(env, obj, JITERATOR_TYPE)) { pyjob = (PyJObject*) pyjiterator_new(); } else if ((*env)->IsInstanceOf(env, obj, JNUMBER_TYPE)) { pyjob = (PyJObject*) pyjnumber_new(); } else { pyjob = PyObject_NEW(PyJObject, &PyJObject_Type); } } pyjob->object = (*env)->NewGlobalRef(env, obj); pyjob->clazz = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, obj)); pyjob->attr = PyList_New(0); pyjob->methods = PyList_New(0); pyjob->fields = PyList_New(0); pyjob->finishAttr = 0; if (pyjobject_init(env, pyjob)) { return (PyObject *) pyjob; } return NULL; }
// pyjmethod_call_internal. where the magic happens. // // okay, some of the magic -- we already the methodId, so we don't have // to reflect. we just have to parse the arguments from python, // check them against the java args, and call the java function. // // easy. :-) PyObject* pyjmethod_call_internal(PyJmethod_Object *self, PyJobject_Object *instance, PyObject *args) { PyObject *result = NULL; const char *str = NULL; JNIEnv *env = NULL; int pos = 0; jvalue *jargs = NULL; int foundArray = 0; /* if params includes pyjarray instance */ PyThreadState *_save; env = pyembed_get_env(); if(!self->parameters) { if(!pyjmethod_init(env, self) || PyErr_Occurred()) return NULL; return pyjmethod_call_internal(self, instance, args); } // validate we can call this method if(!instance->object && self->isStatic != JNI_TRUE) { PyErr_Format(PyExc_RuntimeError, "Instantiate this class before " "calling an object method."); return NULL; } // shouldn't happen if(self->lenParameters != PyTuple_GET_SIZE(args)) { PyErr_Format(PyExc_RuntimeError, "Invalid number of arguments: %i, expected %i.", (int) PyTuple_GET_SIZE(args), self->lenParameters); return NULL; } jargs = (jvalue *) PyMem_Malloc(sizeof(jvalue) * self->lenParameters); // ------------------------------ build jargs off python values // hopefully 40 local references are enough per method call (*env)->PushLocalFrame(env, 40); for(pos = 0; pos < self->lenParameters; pos++) { PyObject *param = NULL; int paramTypeId = -1; jclass paramType = (jclass) (*env)->GetObjectArrayElement(env, self->parameters, pos); param = PyTuple_GetItem(args, pos); /* borrowed */ if(PyErr_Occurred()) { /* borrowed */ goto EXIT_ERROR; } paramTypeId = get_jtype(env, paramType); if(paramTypeId == JARRAY_ID) foundArray = 1; jargs[pos] = convert_pyarg_jvalue(env, param, paramType, paramTypeId, pos); if(PyErr_Occurred()) { /* borrowed */ goto EXIT_ERROR; } (*env)->DeleteLocalRef(env, paramType); } // for parameters // ------------------------------ call based off return type switch(self->returnTypeId) { case JSTRING_ID: { jstring jstr; Py_UNBLOCK_THREADS; if(self->isStatic) jstr = (jstring) (*env)->CallStaticObjectMethodA( env, instance->clazz, self->methodId, jargs); else { // not static, a method on class then. if(!instance->object) jstr = (jstring) (*env)->CallObjectMethodA( env, instance->clazz, self->methodId, jargs); else jstr = (jstring) (*env)->CallObjectMethodA( env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env) && jstr != NULL) { str = (*env)->GetStringUTFChars(env, jstr, 0); result = PyString_FromString(str); (*env)->ReleaseStringUTFChars(env, jstr, str); (*env)->DeleteLocalRef(env, jstr); } break; } case JARRAY_ID: { jobjectArray obj; Py_UNBLOCK_THREADS; if(self->isStatic) obj = (jobjectArray) (*env)->CallStaticObjectMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) obj = (jobjectArray) (*env)->CallObjectMethodA( env, instance->clazz, self->methodId, jargs); else obj = (jobjectArray) (*env)->CallObjectMethodA( env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env) && obj != NULL) result = pyjarray_new(env, obj); break; } case JCLASS_ID: { jobject obj; Py_UNBLOCK_THREADS; if(self->isStatic) obj = (*env)->CallStaticObjectMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) obj = (*env)->CallObjectMethodA(env, instance->clazz, self->methodId, jargs); else obj = (*env)->CallObjectMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env) && obj != NULL) result = pyjobject_new_class(env, obj); break; } case JOBJECT_ID: { jobject obj; Py_UNBLOCK_THREADS; if(self->isStatic) obj = (*env)->CallStaticObjectMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) obj = (*env)->CallObjectMethodA(env, instance->clazz, self->methodId, jargs); else obj = (*env)->CallObjectMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env) && obj != NULL) { result = pyjobject_new(env, obj); } break; } case JINT_ID: { jint ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticIntMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallIntMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallIntMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = Py_BuildValue("i", ret); break; } case JBYTE_ID: { jbyte ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticByteMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallByteMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallByteMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = Py_BuildValue("i", ret); break; } case JCHAR_ID: { jchar ret; char val[2]; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticCharMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallCharMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallCharMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) { val[0] = (char) ret; val[1] = '\0'; result = PyString_FromString(val); } break; } case JSHORT_ID: { jshort ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticShortMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallShortMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallShortMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = Py_BuildValue("i", (int) ret); break; } case JDOUBLE_ID: { jdouble ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticDoubleMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallDoubleMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallDoubleMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = PyFloat_FromDouble(ret); break; } case JFLOAT_ID: { jfloat ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticFloatMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallFloatMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallFloatMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = PyFloat_FromDouble((double) ret); break; } case JLONG_ID: { jlong ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticLongMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallLongMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallLongMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = PyLong_FromLongLong(ret); break; } case JBOOLEAN_ID: { jboolean ret; Py_UNBLOCK_THREADS; if(self->isStatic) ret = (*env)->CallStaticBooleanMethodA( env, instance->clazz, self->methodId, jargs); else { if(!instance->object) ret = (*env)->CallBooleanMethodA(env, instance->clazz, self->methodId, jargs); else ret = (*env)->CallBooleanMethodA(env, instance->object, self->methodId, jargs); } Py_BLOCK_THREADS; if(!process_java_exception(env)) result = Py_BuildValue("i", ret); break; } default: Py_UNBLOCK_THREADS; // i hereby anoint thee a void method if(self->isStatic) (*env)->CallStaticVoidMethodA(env, instance->clazz, self->methodId, jargs); else (*env)->CallVoidMethodA(env, instance->object, self->methodId, jargs); Py_BLOCK_THREADS; process_java_exception(env); break; } PyMem_Free(jargs); (*env)->PopLocalFrame(env, NULL); if(PyErr_Occurred()) return NULL; // re pin array objects if needed if(foundArray) { for(pos = 0; pos < self->lenParameters; pos++) { PyObject *param = PyTuple_GetItem(args, pos); /* borrowed */ if(param && pyjarray_check(param)) pyjarray_pin((PyJarray_Object *) param); } } if(result == NULL) { Py_RETURN_NONE; } return result; EXIT_ERROR: PyMem_Free(jargs); (*env)->PopLocalFrame(env, NULL); return NULL; }
// get value from java object field. // returns new reference. PyObject* pyjfield_get(PyJfield_Object *self) { PyObject *result = NULL; JNIEnv *env; env = pyembed_get_env(); if(!self) { PyErr_Format(PyExc_RuntimeError, "Invalid self object."); return NULL; } if(!self->init) { if(!pyjfield_init(env, self) || PyErr_Occurred()) return NULL; } switch(self->fieldTypeId) { case JSTRING_ID: { jstring jstr; const char *str; if(self->isStatic) jstr = (jstring) (*env)->GetStaticObjectField( env, self->pyjobject->clazz, self->fieldId); else jstr = (jstring) (*env)->GetObjectField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; if(jstr == NULL) { Py_INCREF(Py_None); return Py_None; } str = (*env)->GetStringUTFChars(env, jstr, 0); result = PyString_FromString(str); (*env)->ReleaseStringUTFChars(env, jstr, str); (*env)->DeleteLocalRef(env, jstr); break; } case JCLASS_ID: { jobject obj; if(self->isStatic) obj = (*env)->GetStaticObjectField(env, self->pyjobject->clazz, self->fieldId); else obj = (*env)->GetObjectField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; if(obj == NULL) { Py_INCREF(Py_None); return Py_None; } result = pyjobject_new_class(env, obj); break; } case JOBJECT_ID: { jobject obj; if(self->isStatic) obj = (*env)->GetStaticObjectField(env, self->pyjobject->clazz, self->fieldId); else obj = (*env)->GetObjectField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; if(obj == NULL) { Py_INCREF(Py_None); return Py_None; } result = pyjobject_new(env, obj); break; } case JINT_ID: { jint ret; if(self->isStatic) ret = (*env)->GetStaticIntField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetIntField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = Py_BuildValue("i", ret); break; } case JBYTE_ID: { jbyte ret; if(self->isStatic) ret = (*env)->GetStaticByteField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetByteField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = Py_BuildValue("i", ret); break; } case JCHAR_ID: { jchar ret; char val[2]; if(self->isStatic) ret = (*env)->GetStaticCharField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetCharField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; val[0] = (char) ret; val[1] = '\0'; result = PyString_FromString(val); break; } case JSHORT_ID: { jshort ret; if(self->isStatic) ret = (*env)->GetStaticShortField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetShortField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = Py_BuildValue("i", (int) ret); break; } case JDOUBLE_ID: { jdouble ret; if(self->isStatic) ret = (*env)->GetStaticDoubleField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetDoubleField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = PyFloat_FromDouble(ret); break; } case JFLOAT_ID: { jfloat ret; if(self->isStatic) ret = (*env)->GetStaticFloatField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetFloatField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = PyFloat_FromDouble((double) ret); break; } case JLONG_ID: { jlong ret; if(self->isStatic) ret = (*env)->GetStaticLongField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetLongField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = PyLong_FromLongLong((jeplong) ret); break; } case JBOOLEAN_ID: { jboolean ret; if(self->isStatic) ret = (*env)->GetStaticBooleanField(env, self->pyjobject->clazz, self->fieldId); else ret = (*env)->GetBooleanField(env, self->pyjobject->object, self->fieldId); if(process_java_exception(env)) return NULL; result = Py_BuildValue("i", ret); break; } default: PyErr_Format(PyExc_RuntimeError, "Unknown field type %i.", self->fieldTypeId); Py_INCREF(Py_None); return Py_None; } // shouldn't happen if(result == NULL) { Py_INCREF(Py_None); return Py_None; } return result; }