Skip to content
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

Explicit cast #636

Merged
merged 7 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions doc/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ This changelog *only* contains changes from the *first* pypi release (0.5.4.3) o

- java.util.Map conforms to Python abc.Mapping API.

- float properly follows Java rules for conversion from double.
floats outside of range map to inf and -inf.
- JFloat properly follows Java rules for conversion from JDouble.
JFloats outside of range map to inf and -inf.

- Add support for direct conversion of multi-dimensional primitive arrays
with ``JArray.of(array, [dtype=type])``
Expand All @@ -24,12 +24,24 @@ This changelog *only* contains changes from the *first* pypi release (0.5.4.3) o
- Proxies pass Python exceptions properly rather converting to
java.lang.RuntimeException

- java.lang.Number converts automatically from Python and Java numbers
- java.lang.Number converts automatically from Python and Java numbers.
Java primitive types will cast to their proper box type when passed
to methods and fields taking Number.

- java.lang.Object and java.lang.Number box signed, sized numpy types
(int8, int16, int32, int64, float32, float64) to the Java boxed type
with the same size automatically. Architecture dependent numpy
types map to Long or Double.
types map to Long or Double like other Python types.

- Explicit casting using primitives such as JInt will not produce an
OverflowError. Implicit casting from Python types such as int or float
will.

- Returns for number type primitives will retain their return type
information. These are derived from Python int and float types
thus no change in behavior unless chaining from a Java methods
which is not allowed in Java without a cast.
JBoolean and JChar still produce Python types only.

- Proxies created with JImplements properly implement toString, hashCode,
and equals.
Expand All @@ -40,6 +52,7 @@ This changelog *only* contains changes from the *first* pypi release (0.5.4.3) o
- JProxy instances created with the convert=True argument will automatic
unwrap when passed from Java to Python.


- **0.7.2 - 2-28-2019**

- C++ and Java exceptions hold the traceback as a Python exception
Expand Down
24 changes: 12 additions & 12 deletions jpype/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,18 @@ def startJVM(*args, **kwargs):
_jpype._java_lang_Float = _jpype.JClass("java.lang.Float")
_jpype._java_lang_Double = _jpype.JClass("java.lang.Double")

# Bind types
_jpype.JString.class_ = _jpype._java_lang_String
_jpype.JObject.class_ = _jpype._java_lang_Object
_jtypes.JBoolean.class_ = _jpype._java_lang_Boolean.TYPE
_jtypes.JByte.class_ = _jpype._java_lang_Byte.TYPE
_jtypes.JChar.class_ = _jpype._java_lang_Character.TYPE
_jtypes.JShort.class_ = _jpype._java_lang_Short.TYPE
_jtypes.JInt.class_ = _jpype._java_lang_Integer.TYPE
_jtypes.JLong.class_ = _jpype._java_lang_Long.TYPE
_jtypes.JFloat.class_ = _jpype._java_lang_Float.TYPE
_jtypes.JDouble.class_ = _jpype._java_lang_Double.TYPE

# Table for automatic conversion to objects "JObject(value, type)"
_jpype._object_classes = {}
_jpype._object_classes[bool] = _jpype._java_lang_Boolean
Expand Down Expand Up @@ -283,18 +295,6 @@ def startJVM(*args, **kwargs):
_jpype._type_classes[_jpype.JObject] = _jpype._java_lang_Object
_jinit.runJVMInitializers()

# Bind types
_jpype.JString.class_ = _jpype._java_lang_String
_jpype.JObject.class_ = _jpype._java_lang_Object
_jtypes.JBoolean.class_ = _jpype._java_lang_Boolean.TYPE
_jtypes.JByte.class_ = _jpype._java_lang_Byte.TYPE
_jtypes.JChar.class_ = _jpype._java_lang_Character.TYPE
_jtypes.JShort.class_ = _jpype._java_lang_Short.TYPE
_jtypes.JInt.class_ = _jpype._java_lang_Integer.TYPE
_jtypes.JLong.class_ = _jpype._java_lang_Long.TYPE
_jtypes.JFloat.class_ = _jpype._java_lang_Float.TYPE
_jtypes.JDouble.class_ = _jpype._java_lang_Double.TYPE


def attachToJVM(jvm):
_jpype.attach(jvm)
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_arrayclass.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class JPArrayClass : public JPClass
jint modifiers);
virtual~ JPArrayClass();

virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPMatch::Type findJavaConversion(JPMatch &match);

JPValue newInstance(JPJavaFrame& frame, int length);
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_booleantype.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class JPBooleanType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch& match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
1 change: 1 addition & 0 deletions native/common/include/jp_boxedtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class JPBoxedType : public JPClass
}

jobject box(JPJavaFrame &frame, jvalue v);
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;

protected:
JPPrimitiveType* m_PrimitiveType;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_bytetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class JPByteType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_chartype.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class JPCharType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
12 changes: 9 additions & 3 deletions native/common/include/jp_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class JPClass : public JPResource
m_Host = JPPyObject(JPPyRef::_use, host);
}

PyObject* getHost()
PyTypeObject* getHost()
{
return m_Host.get();
return (PyTypeObject*) m_Host.get();
}

void setHints(PyObject* host)
Expand Down Expand Up @@ -132,9 +132,15 @@ class JPClass : public JPResource

/** Create a new Python object to wrap a Java value.
*
* Some conversion convert to a Python type such as Java boolean and char.
* Null pointers match to Python None. Objects convert automatically to
* the most derived type. To disable this behavior the cast option can be
* specified.
*
* @param cast force the wrapper to be the defined type.
* @return a new Python object.
*/
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val);
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast);
Comment on lines -137 to +143
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are adding an extra "cast" argument. If set to true it disables all of the Python conversions and forces the type to match.


/**
* Get the Java value representing as an object.
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_doubletype.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class JPDoubleType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame &frame, jclass, jmethodID, jvalue*) override;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_floattype.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class JPFloatType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_inttype.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class JPIntType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch& match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_longtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class JPLongType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch& match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
37 changes: 20 additions & 17 deletions native/common/include/jp_primitive_accessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class JPPrimitiveArrayAccessor
((&_frame)->*_release)(a, _elem, JNI_ABORT);
}

};
} ;

template <class type_t> PyObject *convertMultiArray(
JPJavaFrame &frame,
Expand Down Expand Up @@ -145,7 +145,7 @@ template <class type_t> PyObject *convertMultiArray(
type = frame.findClassForObject(out);
jvalue v;
v.l = out;
return type->convertToPythonObject(frame, v).keep();
return type->convertToPythonObject(frame, v, false).keep();
}

template <typename base_t>
Expand All @@ -164,16 +164,25 @@ class JPConversionLong : public JPConversion
virtual jvalue convert(JPMatch &match) override
{
jvalue res;
jlong val = PyLong_AsLongLong(match.object);
if (val == -1)
JP_PY_CHECK();
base_t::field(res) = (typename base_t::type_t) base_t::assertRange(val);
if (match.type == JPMatch::_exact)
{
jlong val = (jlong) PyLong_AsUnsignedLongLongMask(match.object);
if (val == -1)
JP_PY_CHECK();
base_t::field(res) = (typename base_t::type_t) val;
} else
{
jlong val = (jlong) PyLong_AsLongLong(match.object);
if (val == -1)
JP_PY_CHECK();
base_t::field(res) = (typename base_t::type_t) base_t::assertRange(val);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We select the type of conversion here. We need different functions based on the whether it is an implicit or a user requested cast.

return res;
}
} ;

template <typename base_t>
class JPConversionLongNumber : public JPConversion
class JPConversionLongNumber : public JPConversionLong<base_t>
{
public:

Expand All @@ -187,17 +196,11 @@ class JPConversionLongNumber : public JPConversion

virtual jvalue convert(JPMatch &match) override
{
jvalue res;
PyObject *obj = PyNumber_Long(match.object);
JP_PY_CHECK();
jlong val = PyLong_AsLongLong(obj);
Py_DECREF(obj);
if (val == -1)
JP_PY_CHECK();
base_t::field(res) = (typename base_t::type_t) base_t::assertRange(val);
return res;
JPPyObject obj = JPPyObject(JPPyRef::_call, PyNumber_Long(match.object));
match.object = obj.get();
return JPConversionLong<base_t>::convert(match);
}
};
} ;

template <typename base_t>
class JPConversionLongWiden : public JPConversion
Expand Down
3 changes: 3 additions & 0 deletions native/common/include/jp_primitivetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class JPPrimitiveType : public JPClass

virtual PyObject *newMultiArray(JPJavaFrame &frame,
JPPyBuffer& view, int subs, int base, jobject dims) = 0;

// Helper for Long types
PyObject *convertLong(PyTypeObject* wrapper, PyLongObject* tmp);
} ;

#endif
2 changes: 1 addition & 1 deletion native/common/include/jp_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class JPProxyType : public JPClass
virtual~ JPProxyType();

public: // JPClass implementation
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;

private:
JPClassRef m_ProxyClass;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_shorttype.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class JPShortType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
virtual JPValue getValueFromObject(const JPValue& obj) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_stringtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class JPStringType : public JPClass
virtual ~JPStringType();

public:
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;
JPMatch::Type findJavaConversion(JPMatch& match) override;
virtual JPValue newInstance(JPJavaFrame& frame, JPPyObjectVector& args) override;
} ;
Expand Down
2 changes: 1 addition & 1 deletion native/common/include/jp_voidtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class JPVoidType : public JPPrimitiveType
}

virtual JPMatch::Type findJavaConversion(JPMatch &match) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val) override;
virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override;

virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override;
virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override;
Expand Down
12 changes: 10 additions & 2 deletions native/common/jp_arrayclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,18 @@ JPMatch::Type JPArrayClass::findJavaConversion(JPMatch &match)
JP_TRACE_OUT;
}

JPPyObject JPArrayClass::convertToPythonObject(JPJavaFrame& frame, jvalue val)
JPPyObject JPArrayClass::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast)
{
JP_TRACE_IN("JPArrayClass::convertToPythonObject");
return PyJPValue_create(frame, JPValue(this, val));
if (!cast)
{
if (value.l == NULL)
return JPPyObject::getNone();
}
JPPyObject wrapper = PyJPClass_create(frame, this);
JPPyObject obj = PyJPArray_create(frame, (PyTypeObject*) wrapper.get(), JPValue(this, value));
PyJPValue_assignJavaSlot(frame, obj.get(), JPValue(this, value));
return obj;
JP_TRACE_OUT;
}

Expand Down
14 changes: 7 additions & 7 deletions native/common/jp_booleantype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ JPBooleanType::~JPBooleanType()
{
}

JPPyObject JPBooleanType::convertToPythonObject(JPJavaFrame& frame, jvalue val)
JPPyObject JPBooleanType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast)
{
return JPPyObject(JPPyRef::_call, PyBool_FromLong(val.z));
}
Expand Down Expand Up @@ -113,14 +113,14 @@ JPPyObject JPBooleanType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID
{
jvalue v;
field(v) = frame.GetStaticBooleanField(c, fid);
return convertToPythonObject(frame, v);
return convertToPythonObject(frame, v, false);
}

JPPyObject JPBooleanType::getField(JPJavaFrame& frame, jobject c, jfieldID fid)
{
jvalue v;
field(v) = frame.GetBooleanField(c, fid);
return convertToPythonObject(frame, v);
return convertToPythonObject(frame, v, false);
}

JPPyObject JPBooleanType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val)
Expand All @@ -130,7 +130,7 @@ JPPyObject JPBooleanType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodI
JPPyCallRelease call;
field(v) = frame.CallStaticBooleanMethodA(claz, mth, val);
}
return convertToPythonObject(frame, v);
return convertToPythonObject(frame, v, false);
}

JPPyObject JPBooleanType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val)
Expand All @@ -143,7 +143,7 @@ JPPyObject JPBooleanType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz,
else
field(v) = frame.CallNonvirtualBooleanMethodA(obj, clazz, mth, val);
}
return convertToPythonObject(frame, v);
return convertToPythonObject(frame, v, false);
}

void JPBooleanType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj)
Expand Down Expand Up @@ -227,7 +227,7 @@ JPPyObject JPBooleanType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx)
frame.GetBooleanArrayRegion(array, ndx, 1, &val);
jvalue v;
field(v) = val;
return convertToPythonObject(frame, v);
return convertToPythonObject(frame, v, false);
}

void JPBooleanType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj)
Expand Down Expand Up @@ -291,4 +291,4 @@ PyObject *JPBooleanType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, i
frame, this, &pack, "z",
buffer, subs, base, dims);
JP_TRACE_OUT;
}
}
Loading