ninia/jep

can not use in operator when passing java ArrayList<Integer> to python, but ArrayList<String> works well

Closed this issue · 5 comments

Describe the bug
I passed ArrayList and ArrayList to python env. The python code is as follows,
`if "1" in stringListA:
#do something

if 1 in integerListB:
#do something else`

stringListA = ["1"];integerListB = [1];in java and use
Object result = interp.invoke("mainFunc", new Object[] { inputCodeParams });
sending these two lists in a map named inputCodeParams to python env.
The program entered the first branch, but it didn't enter the second one. I tested that the integerListB did have the __contains__ method, but the in operator doesn't work correctly. Is there any different support between these two types? Or should I modify my usage?
To Reproduce
write the code above

Expected behavior
enter the second branch

Environment (please complete the following information):

  • OS Platform, Distribution, and Version: linux
  • Python Distribution and Version: python 3.11
  • Java Distribution and Version: 11
  • Jep Version: the newest version

btw when I used list(integerListB) casting the type to python list, the 'in' operator works correctly.

The __contains__ implementation for Java collections converts the Python object into a Java object and calls contains() on the Java collection. A Python int is converted to a Long in Java so the Long is not found in the list of Integers. It would work better if you use an ArrayList or if you convert the Python int to an Integer before checking if it is in the List. Here is some code in the jep interpreter that shows some examples of interacting with different type of ArrayList in python

>>> from java.util import ArrayList
>>> from java.lang import Integer, Long
>>> stringList = ArrayList(["1"])
>>> intList = ArrayList([Integer(1)])
>>> longList = ArrayList([Long(1)])
>>> "1" in stringList
True
>>> 1 in intList
False
>>> 1 in longList
True
>>> Integer(1) in intList
True
>>> Integer(1) in longList
False
>>> Long(1) in intList
False
>>> Long(1) in longList
True

The __contains__ implementation for Java collections converts the Python object into a Java object and calls contains() on the Java collection. A Python int is converted to a Long in Java so the Long is not found in the list of Integers. It would work better if you use an ArrayList or if you convert the Python int to an Integer before checking if it is in the List. Here is some code in the jep interpreter that shows some examples of interacting with different type of ArrayList in python

>>> from java.util import ArrayList
>>> from java.lang import Integer, Long
>>> stringList = ArrayList(["1"])
>>> intList = ArrayList([Integer(1)])
>>> longList = ArrayList([Long(1)])
>>> "1" in stringList
True
>>> 1 in intList
False
>>> 1 in longList
True
>>> Integer(1) in intList
True
>>> Integer(1) in longList
False
>>> Long(1) in intList
False
>>> Long(1) in longList
True

@bsteffensmeier Thanks very much. Is there any other method to solve this problem if I want to retain python programming habits. I don't understand that why does "in" operation convert python object to java object. why not just use it in python env?

Is there any other method to solve this problem if I want to retain python programming habits.

  1. You can extend ArrayList and override contains to convert Long to Integer.
  2. You can use an int[] instead of ArrayList
  3. You can extend ArrayList and implement __contains__ to take an Integer
  4. You can convert your ArrayList to a Python list
  5. You can use an ArrayList instead of ArrayList

I don't understand that why does "in" operation convert python object to java object. why not just use it in python env?

Since ArrayList is a Java List it only contains Java objects so the only way to test if a Python object is in the List is to convert it to a Java object. It works how you expect when you use list(integerListB) because you no longer have a Java List.