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

Fix iterators py2 #507

Merged
merged 4 commits into from
Apr 11, 2020
Merged
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
76 changes: 54 additions & 22 deletions jnius/reflect.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import division
__all__ = ('autoclass', 'ensureclass', 'protocol_map')
from six import with_metaclass
import logging
from collections import defaultdict
from logging import getLogger, DEBUG

from six import with_metaclass, PY2

from .jnius import (
JavaClass, MetaJavaClass, JavaMethod, JavaStaticMethod,
JavaField, JavaStaticField, JavaMultipleMethod, find_javaclass,
JavaException
)

log = logging.getLogger(__name__)
from collections import defaultdict
__all__ = ('autoclass', 'ensureclass', 'protocol_map')

log = getLogger(__name__)


class Class(with_metaclass(MetaJavaClass, JavaClass)):
Expand Down Expand Up @@ -233,17 +235,17 @@ def autoclass(clsname):
classDict['__javaconstructor__'] = constructors

class_hierachy = list(identify_hierarchy(c, 0, not c.isInterface()))

log.debug("autoclass(%s) intf %r hierarchy is %s" % (clsname,c.isInterface(),str(class_hierachy)))
cls_done=set()

cls_methods=defaultdict(list)

# we now walk the hierarchy, from top of the tree, identifying methods
# hopefully we start at java.lang.Object
# hopefully we start at java.lang.Object
for cls,level in class_hierachy:
# dont analyse a given class more than once.
# many interfaces can lead to java.lang.Object
# many interfaces can lead to java.lang.Object
if cls in cls_done:
continue
cls_done.add(cls)
Expand All @@ -256,7 +258,7 @@ def autoclass(clsname):
for index, method in enumerate(methods):
name = methods_name[index]
cls_methods[name].append((cls, method, level))

# having collated the mthods, identify if there are any with the same name
for name in cls_methods:
if len(cls_methods[name]) == 1:
Expand All @@ -267,7 +269,7 @@ def autoclass(clsname):
sig = '({0}){1}'.format(
''.join([get_signature(x) for x in method.getParameterTypes()]),
get_signature(method.getReturnType()))
if log.level <= logging.DEBUG:
if log.isEnabledFor(DEBUG):
log_method(method, name, sig)
classDict[name] = (JavaStaticMethod if static else JavaMethod)(sig, varargs=varargs)
if name != 'getClass' and bean_getter(name) and len(method.getParameterTypes()) == 0:
Expand All @@ -277,7 +279,7 @@ def autoclass(clsname):
# multiple signatures
signatures = []
log.debug("method %s has %d multiple signatures in hierarchy of cls %s" % (name, len(cls_methods[name]), c))

paramsig_to_level=defaultdict(lambda: float('inf'))
# we now identify if any have the same signature, as we will call the _lowest_ in the hierarchy,
# as reflected in min level
Expand All @@ -296,8 +298,8 @@ def autoclass(clsname):

return_sig = get_signature(method.getReturnType())
sig = '({0}){1}'.format(param_sig, return_sig)
if log.level <= logging.DEBUG:

if log.isEnabledFor(DEBUG):
log_method(method, name, sig)
signatures.append((sig, Modifier.isStatic(method.getModifiers()), method.isVarArgs()))

Expand All @@ -309,7 +311,7 @@ def autoclass(clsname):
cls_name = cls.getName()
if cls_name in protocol_map:
for pname, plambda in protocol_map[cls_name].items():
classDict[pname] = plambda
classDict[pname] = plambda

for field in c.getFields():
static = Modifier.isStatic(field.getModifiers())
Expand All @@ -322,7 +324,9 @@ def autoclass(clsname):
MetaJavaClass,
clsname,
(JavaClass, ),
classDict)
classDict
)


def _getitem(self, index):
''' dunder method for List '''
Expand All @@ -345,36 +349,64 @@ def _map_getitem(self, k):
raise KeyError()
return rtr


class Py2Iterator(object):
'''
In py2 the next() is called on the iterator, not __next__
so we need to wrap the java call to check hasNext to conform to
python's api
'''
def __init__(self, java_iterator):
self.java_iterator = java_iterator

def __iter__(self):
return self

def next(self):
log.debug("monkey patched next() called")
if not self.java_iterator.hasNext():
raise StopIteration()
return self.java_iterator.next()


def safe_iterator(iterator):
if PY2:
return Py2Iterator(iterator)
return iterator


def _iterator_next(self):
''' dunder method for java.util.Iterator'''
if not self.hasNext():
raise StopIteration()

return self.next()

# protocol_map is a user-accessible API for patching class instances with additional methods

# protocol_map is a user-accessible API for patching class instances with additional methods
protocol_map = {
'java.util.Collection' : {
'__len__' : lambda self: self.size(),
'__contains__' : lambda self, item: self.contains(item),
'__delitem__' : lambda self, item: self.remove(item)
},
'java.util.List' : {
'__getitem__' : _getitem
'__getitem__' : _getitem
},
'java.util.Map' : {
'__setitem__' : lambda self, k, v : self.put(k,v),
'__getitem__' : _map_getitem,
'__delitem__' : lambda self, item: self.remove(item),
'__len__' : lambda self: self.size(),
'__contains__' : lambda self, item: self.containsKey(item),
'__iter__' : lambda self: self.keySet().iterator()
'__iter__' : lambda self: safe_iterator(self.keySet().iterator())
},
'java.util.Iterator' : {
'__iter__' : lambda self: self,
'__next__' : _iterator_next
'__iter__' : lambda self: safe_iterator(self),
'__next__' : _iterator_next,
},
'java.lang.Iterable' : {
'__iter__' : lambda self: self.iterator(),
'__iter__' : lambda self: safe_iterator(self.iterator()),
},
# this also addresses java.io.Closeable
'java.lang.AutoCloseable' : {
Expand All @@ -391,4 +423,4 @@ def _iterator_next(self):
'__le__' : lambda self, other: self.compareTo(other) <= 0,
'__ge__' : lambda self, other: self.compareTo(other) >= 0,
}
}
}