Skip to content

Commit

Permalink
Merge pull request #687 from Thrameos/jstring
Browse files Browse the repository at this point in the history
Handle nulls in strings
  • Loading branch information
marscher authored Apr 19, 2020
2 parents fde9a09 + 944e03f commit 616ed89
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 39 deletions.
30 changes: 30 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,33 @@ jobs:
inputs:
testResultsFiles: 'build/test/test.xml'
testRunTitle: 'Publish windows test results for Python $(python.version)'

- job: Test_debug
condition: eq(1,2)
strategy:
matrix:
linux-3.8:
imageName: "ubuntu-16.04"
jdk_version: "1.11"
python.version: '3.8'
pool:
vmImage: $(imageName)
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
- script: |
sudo apt install gdb
python setup.py sdist
pip install dist/*
displayName: 'Build module'
- script: python -c "import jpype"
displayName: 'Check module'
- script: |
python setup.py test_java
pip install -r test-requirements.txt
pip install numpy jedi
gdb -ex 'handle SIGSEGV nostop noprint pass' -ex "run -m pytest -v test/jpypetest/test_jstring.py --checkjni" -ex "bt" -ex "quit" python
displayName: 'Debug module'
24 changes: 2 additions & 22 deletions jpype/_jstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@ class _JStringProto(object):
def __add__(self, other):
return self.concat(other)

def __eq__(self, other):
if isinstance(other, JString):
return self.equals(other)
return str(self) == other

def __ne__(self, other):
if isinstance(other, JString):
return not self.equals(other)
return str(self) != other

def __len__(self):
return self.length()

Expand All @@ -62,22 +52,12 @@ def __getitem__(self, i):
raise IndexError("Array index exceeds length")
return self.charAt(i)

def __lt__(self, other):
return self.compareTo(other) < 0

def __le__(self, other):
return self.compareTo(other) <= 0

def __gt__(self, other):
return self.compareTo(other) > 0

def __ge__(self, other):
return self.compareTo(other) >= 0

def __contains__(self, other):
return self.contains(other)

def __hash__(self):
if self == None: # lgtm [py/test-equals-none]
return hash(None)
return self.__str__().__hash__()

def __repr__(self):
Expand Down
3 changes: 1 addition & 2 deletions native/common/include/jp_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class JPContext
public:
friend class JPJavaFrame;
friend class JPypeException;
friend class JPClass;

JPContext();
virtual ~JPContext();
Expand Down Expand Up @@ -223,8 +224,6 @@ class JPContext
jint(JNICALL * GetCreatedJVMs_Method)(JavaVM **pvm, jsize size, jsize * nVms);

private:
friend class JPJavaFrame;
friend class JPClass;
JPContext(const JPContext& orig);

JavaVM *m_JavaVM;
Expand Down
9 changes: 4 additions & 5 deletions native/python/pyjp_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static PyObject *PyJPObject_compare(PyObject *self, PyObject *other, int op)
}
if (op != Py_EQ)
{
PyErr_Format(PyExc_TypeError, "'%s' not supported with Java object", op_names[op]);
PyErr_Format(PyExc_TypeError, "'%s' not supported with Java `%s`", op_names[op], Py_TYPE(self)->tp_name);
return NULL;
}

Expand Down Expand Up @@ -129,7 +129,7 @@ static PyObject *PyJPComparable_compare(PyObject *self, PyObject *other, int op)
if (self == Py_None || javaSlot0 == NULL ||
(!javaSlot0->getClass()->isPrimitive() && javaSlot0->getValue().l == NULL))
null0 = true;
if (other == Py_None || ( javaSlot0 != NULL &&
if (other == Py_None || (javaSlot1 != NULL &&
!javaSlot1->getClass()->isPrimitive() && javaSlot1->getValue().l == NULL))
null1 = true;

Expand All @@ -138,8 +138,6 @@ static PyObject *PyJPComparable_compare(PyObject *self, PyObject *other, int op)

if (!null0)
obj0 = javaSlot0->getValue().l;
if (!null1)
obj1 = javaSlot1->getValue().l;

if (!null0 && !null1 && javaSlot1 == NULL)
{
Expand All @@ -160,7 +158,8 @@ static PyObject *PyJPComparable_compare(PyObject *self, PyObject *other, int op)
if (!cls2->findJavaConversion(match))
JP_RAISE(PyExc_TypeError, "Type is not comparable");
obj1 = match.convert().l;
}
} else if (!null1 && javaSlot1 != NULL)
obj1 = javaSlot1->getValue().l;

switch (op)
{
Expand Down
8 changes: 4 additions & 4 deletions native/python/pyjp_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ PyObject* PyJPValue_str(PyObject* self)
if (cls->isPrimitive())
JP_RAISE(PyExc_TypeError, "toString requires a Java object");

if (value->getValue().l == NULL)
return JPPyString::fromStringUTF8("null").keep();

if (cls == context->_java_lang_String)
{
PyObject *cache;
Expand All @@ -183,10 +186,7 @@ PyObject* PyJPValue_str(PyObject* self)
}
jstring jstr = (jstring) value->getValue().l;
string str;
if (jstr == NULL)
str = "null"; // match Java behavior on printing null pointers
else
str = frame.toStringUTF8(jstr);
str = frame.toStringUTF8(jstr);
cache = JPPyString::fromStringUTF8(str).keep();
PyDict_SetItemString(dict.get(), "_jstr", cache);
Py_INCREF(cache);
Expand Down
4 changes: 2 additions & 2 deletions test/harness/jpype/attr/Test1.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ public String[] testStringArray(String[] vals)

public String stringValue = "Foo";
public char charValue = 'a';
public static Object objectValue= new Integer(234);
public static Object objectValue= (int)234;

public static void reset()
{
objectValue= new Integer(234);
objectValue= (int)234;
}

public Object getSubClass()
Expand Down
24 changes: 20 additions & 4 deletions test/jpypetest/test_jobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,19 @@ def testStrPrimitive(self):
_jpype._JObject.__str__(JInt(1))

def testGetAttrFail(self):
js = JString("a")
jo = JClass("java.lang.Object")()
with self.assertRaisesRegex(TypeError, "must be string"):
getattr(js, object())
getattr(jo, object())

def testSetAttrFail(self):
js = JString("a")
jo = JClass("java.lang.Object")()
with self.assertRaisesRegex(TypeError, "must be string"):
setattr(js, object(), "b")
setattr(jo, object(), 1)

def testSetAttrFail2(self):
fixture = JClass("jpype.common.Fixture")()
with self.assertRaisesRegex(AttributeError, "is not settable"):
setattr(fixture,"callObject",4)

def testJavaPrimitives(self):
self.assertIsInstance(
Expand Down Expand Up @@ -249,3 +254,14 @@ def testNumpyPrimitives(self):
self.assertIsInstance(self.fixture.callObject(np.float32(1)), java.lang.Float)
self.assertIsInstance(self.fixture.callObject(np.float64(1)), java.lang.Double)

def testCompare(self):
jo = JClass("java.lang.Object")()
with self.assertRaisesRegex(TypeError, 'not supported'):
jo<0
with self.assertRaisesRegex(TypeError, 'not supported'):
jo<=0
with self.assertRaisesRegex(TypeError, 'not supported'):
jo>0
with self.assertRaisesRegex(TypeError, 'not supported'):
jo>=0

34 changes: 34 additions & 0 deletions test/jpypetest/test_jstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,37 @@ def testStringDictKey3(self):

def testNullString(self):
self.assertEqual(str(JObject(None, JString)), "null")

def testNullCompare(self):
jsn = JObject(None, JString)
self.assertFalse("a" == jsn)
self.assertTrue("a" != jsn)
self.assertFalse(jsn == "a")
self.assertTrue(jsn != "a")
self.assertTrue(jsn == jsn)
self.assertFalse(jsn != jsn)
with self.assertRaises(ValueError):
jsn < "a"
with self.assertRaises(ValueError):
jsn <= "a"
with self.assertRaises(ValueError):
jsn > "a"
with self.assertRaises(ValueError):
jsn >= "a"
with self.assertRaises(ValueError):
"a" < jsn
with self.assertRaises(ValueError):
"a" <= jsn
with self.assertRaises(ValueError):
"a" > jsn
with self.assertRaises(ValueError):
"a" >= jsn

def testNullAdd(self):
jsn = JObject(None, JString)
with self.assertRaises(ValueError):
jsn+"a"

def testNullHash(self):
jsn = JObject(None, JString)
self.assertEqual(hash(jsn), hash(None))

0 comments on commit 616ed89

Please sign in to comment.