-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function for converting Python values to an explicit Java type #128
Changes from 22 commits
9bdbaeb
06df869
d599bf0
1676e46
d43e8df
20444d6
5a3fdf0
ea60b1f
61bde34
877a99b
36ed7a0
b49090b
3dea91c
0996fac
2794f6b
e20757b
525362d
2d252c3
c25ab7c
eaff9d6
dc161cf
d204645
1d884a8
c61869d
010feaf
b060d17
bdd1f72
efab329
4182956
f364d46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,4 @@ Vagrantfile | |
*.so | ||
*.dll | ||
|
||
.vscode/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ PyObject* JPy_create_jvm(PyObject* self, PyObject* args, PyObject* kwds); | |
PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args); | ||
PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds); | ||
PyObject* JPy_cast(PyObject* self, PyObject* args); | ||
PyObject* JPy_as_jobj(PyObject* self, PyObject* args); | ||
PyObject* JPy_array(PyObject* self, PyObject* args); | ||
PyObject* JPy_byte_buffer(PyObject* self, PyObject* args); | ||
|
||
|
@@ -61,6 +62,11 @@ static PyMethodDef JPy_Functions[] = { | |
"cast(obj, type) - Cast the given Java object to the given Java type (type name or type object). " | ||
"Returns None if the cast is not possible."}, | ||
|
||
{"as_jobj", JPy_as_jobj, METH_VARARGS, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is cool - previously, we could do this, it just required explicit java code: public class MyClass {
public static MyJavaType identity(MyJavaType x) {
return x;
}
} jobj = jpy.get_type('MyClass').identity(pobj) I'm assuming these are the semantics you are after? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, basically I had two parallel lists, one of java types and one of python values (in practice strings/numbers), and I wanted to stick the python values into a java There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not too crazy about the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm definitely open to changing it. I went with @devinrsmith what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think "as" gives off the wrong semantic notion, somewhat akin to zero-cost. While the same could be said about I'm also not the biggest fan of trying to save a few characters; my vote would be for |
||
"as_jobj(obj, type) - Convert the given Python object to the given Java type (type name or type object). " | ||
"Returns None if the conversion is not possible. If the Java type is a primitive, the returned object " | ||
"will be of the corresponding boxed type."}, | ||
|
||
{"array", JPy_array, METH_VARARGS, | ||
"array(name, init) - Return a new Java array of given Java type (type name or type object) and initializer (array length or sequence). " | ||
"Possible primitive types are 'boolean', 'byte', 'char', 'short', 'int', 'long', 'float', and 'double'."}, | ||
|
@@ -451,7 +457,7 @@ PyObject* JPy_create_jvm(PyObject* self, PyObject* args, PyObject* kwds) | |
if (JPy_JVM != NULL) { | ||
JPy_DIAG_PRINT(JPy_DIAG_F_JVM + JPy_DIAG_F_ERR, "JPy_create_jvm: WARNING: Java VM is already running.\n"); | ||
JPy_DECREF(options); | ||
return Py_BuildValue(""); | ||
return JPy_FROM_JVOID(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replaced the handful of |
||
} | ||
|
||
if (!PySequence_Check(options)) { | ||
|
@@ -513,7 +519,7 @@ PyObject* JPy_create_jvm(PyObject* self, PyObject* args, PyObject* kwds) | |
return NULL; | ||
} | ||
|
||
return Py_BuildValue(""); | ||
return JPy_FROM_JVOID(); | ||
} | ||
|
||
PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args) | ||
|
@@ -526,7 +532,7 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args) | |
JPy_JVM = NULL; | ||
} | ||
|
||
return Py_BuildValue(""); | ||
return JPy_FROM_JVOID(); | ||
} | ||
|
||
PyObject* JPy_get_type_internal(JNIEnv* jenv, PyObject* self, PyObject* args, PyObject* kwds) | ||
|
@@ -551,41 +557,41 @@ PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds) | |
PyObject* JPy_cast_internal(JNIEnv* jenv, PyObject* self, PyObject* args) | ||
{ | ||
PyObject* obj; | ||
PyObject* objType; | ||
JPy_JType* type; | ||
PyObject* targetTypeArg; // can be a string PyObject (i.e. JPy_IS_STR) or a JPy_JType | ||
JPy_JType* targetTypeParsed; // the actual type that targetTypeArg is processed as | ||
jboolean inst; | ||
|
||
if (!PyArg_ParseTuple(args, "OO:cast", &obj, &objType)) { | ||
if (!PyArg_ParseTuple(args, "OO:cast", &obj, &targetTypeArg)) { | ||
return NULL; | ||
} | ||
|
||
if (obj == Py_None) { | ||
return Py_BuildValue(""); | ||
return JPy_FROM_JNULL(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not appropriate to use here unless we are converting from a null java object. |
||
} | ||
|
||
if (!JObj_Check(obj)) { | ||
PyErr_SetString(PyExc_ValueError, "cast: argument 1 (obj) must be a Java object"); | ||
return NULL; | ||
} | ||
|
||
if (JPy_IS_STR(objType)) { | ||
const char* typeName = JPy_AS_UTF8(objType); | ||
type = JType_GetTypeForName(jenv, typeName, JNI_FALSE); | ||
if (type == NULL) { | ||
if (JPy_IS_STR(targetTypeArg)) { | ||
const char* typeName = JPy_AS_UTF8(targetTypeArg); | ||
targetTypeParsed = JType_GetTypeForName(jenv, typeName, JNI_FALSE); | ||
if (targetTypeParsed == NULL) { | ||
return NULL; | ||
} | ||
} else if (JType_Check(objType)) { | ||
type = (JPy_JType*) objType; | ||
} else if (JType_Check(targetTypeArg)) { | ||
targetTypeParsed = (JPy_JType*) targetTypeArg; | ||
} else { | ||
PyErr_SetString(PyExc_ValueError, "cast: argument 2 (obj_type) must be a Java type name or Java type object"); | ||
return NULL; | ||
} | ||
|
||
inst = (*jenv)->IsInstanceOf(jenv, ((JPy_JObj*) obj)->objectRef, type->classRef); | ||
inst = (*jenv)->IsInstanceOf(jenv, ((JPy_JObj*) obj)->objectRef, targetTypeParsed->classRef); | ||
if (inst) { | ||
return (PyObject*) JObj_FromType(jenv, (JPy_JType*) objType, ((JPy_JObj*) obj)->objectRef); | ||
return (PyObject*) JObj_FromType(jenv, (JPy_JType*) targetTypeParsed, ((JPy_JObj*) obj)->objectRef); | ||
} else { | ||
return Py_BuildValue(""); | ||
return JPy_FROM_JNULL(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
} | ||
} | ||
|
||
|
@@ -594,6 +600,77 @@ PyObject* JPy_cast(PyObject* self, PyObject* args) | |
JPy_FRAME(PyObject*, NULL, JPy_cast_internal(jenv, self, args), 16) | ||
} | ||
|
||
PyObject* JPy_as_jobj_internal(JNIEnv* jenv, PyObject* self, PyObject* args) | ||
{ | ||
PyObject* obj; | ||
PyObject* targetTypeArg; // can be a string PyObject (i.e. JPy_IS_STR) or a JPy_JType | ||
JPy_JType* targetTypeParsed; // the actual type that targetTypeArg is processed as | ||
jboolean inst; | ||
|
||
PyObject* resultObj; | ||
jobject objectRef; | ||
|
||
// Parse the 'args' from Python into 'obj'/'objType'. | ||
if (!PyArg_ParseTuple(args, "OO:as_jobj", &obj, &targetTypeArg)) { | ||
return NULL; | ||
} | ||
|
||
if (obj == Py_None) { | ||
return JPy_FROM_JNULL(); | ||
} | ||
|
||
if (JPy_IS_STR(targetTypeArg)) { | ||
const char* typeName = JPy_AS_UTF8(targetTypeArg); | ||
targetTypeParsed = JType_GetTypeForName(jenv, typeName, JNI_FALSE); | ||
if (targetTypeParsed == NULL) { | ||
return NULL; | ||
} | ||
} else if (JType_Check(targetTypeArg)) { | ||
targetTypeParsed = (JPy_JType*) targetTypeArg; | ||
} else { | ||
PyErr_SetString(PyExc_ValueError, "cast: argument 2 (obj_type) must be a Java type name or Java type object"); | ||
return NULL; | ||
} | ||
|
||
// If the input obj is a Java object, and it is already of the specified target type, | ||
// then just cast it. | ||
if (JObj_Check(obj)) { | ||
inst = (*jenv)->IsInstanceOf(jenv, ((JPy_JObj*) obj)->objectRef, targetTypeParsed->classRef); | ||
if (inst) { | ||
return (PyObject*) JObj_FromType(jenv, (JPy_JType*) targetTypeParsed, ((JPy_JObj*) obj)->objectRef); | ||
} | ||
} | ||
|
||
// Convert the Python object to the specified Java type | ||
if (JPy_AsJObjectWithType(jenv, obj, &objectRef, targetTypeParsed) < 0) { | ||
return NULL; | ||
} | ||
|
||
// Create a global reference for the objectRef (so it is valid after we exit this frame) | ||
objectRef = (*jenv)->NewGlobalRef(jenv, objectRef); | ||
if (objectRef == NULL) { | ||
PyErr_NoMemory(); | ||
return NULL; | ||
} | ||
|
||
// Create a PyObject (JObj) to hold the result | ||
resultObj = (JPy_JObj*) PyObject_New(JPy_JObj, JTYPE_AS_PYTYPE(targetTypeParsed)); | ||
if (resultObj == NULL) { | ||
(*jenv)->DeleteGlobalRef(jenv, objectRef); | ||
return NULL; | ||
} | ||
// Store the reference to the converted object in the result JObj | ||
((JPy_JObj*) resultObj)->objectRef = objectRef; | ||
|
||
return (PyObject*) resultObj; | ||
} | ||
|
||
|
||
PyObject* JPy_as_jobj(PyObject* self, PyObject* args) | ||
{ | ||
JPy_FRAME(PyObject*, NULL, JPy_as_jobj_internal(jenv, self, args), 16) | ||
} | ||
|
||
PyObject* JPy_array_internal(JNIEnv* jenv, PyObject* self, PyObject* args) | ||
{ | ||
JPy_JType* componentType; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you comment on the effect of this? It looks like you removed the JPy_JObject condition from Long / Float, but not Double?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the cases I changed were:
and:
in both case, the second
type == JPy_JObject
test will always be false — for the first case, we will have already landed inJType_CreateJavaNumberFromPythonInt
and in the second case we'd hitJType_CreateJavaDoubleObject
.