diff -r 06161ebf74ee -r 99e275768a6c Lib/test/test_dict_jy.py --- a/Lib/test/test_dict_jy.py Mon May 19 09:02:22 2014 +0100 +++ b/Lib/test/test_dict_jy.py Thu May 22 22:07:01 2014 -0700 @@ -120,6 +120,13 @@ x.put((1,2), "xyz") y = dict(x) self.assertEqual(set(y.items()), set([('a', 1), ('b', 2), ('c', 3), ((1,2), "xyz")])) + + def test_hashmap_builtin_pymethods(self): + x = java.util.HashMap() + x['a'] = 1 + x[(1, 2)] = 'xyz' + self.assertEqual({tup for tup in x.iteritems()}, {('a', 1), ((1, 2), 'xyz')}) + def test_hashtable(self): x = java.util.Hashtable() x.put('a', 1) diff -r 06161ebf74ee -r 99e275768a6c src/org/python/core/PyJavaType.java --- a/src/org/python/core/PyJavaType.java Mon May 19 09:02:22 2014 +0100 +++ b/src/org/python/core/PyJavaType.java Thu May 22 22:07:01 2014 -0700 @@ -531,11 +531,10 @@ } else { dict.__setitem__("__init__", reflctr); } - for (Map.Entry, PyBuiltinMethod[]> entry : getCollectionProxies().entrySet()) { - if (entry.getKey() == forClass) { - for (PyBuiltinMethod meth : entry.getValue()) { - addMethod(meth); - } + PyBuiltinMethod[] collectionProxyMethods = getCollectionProxies().get(forClass); + if (collectionProxyMethods != null) { + for (PyBuiltinMethod meth : collectionProxyMethods) { + addMethod(meth); } } if (ClassDictInit.class.isAssignableFrom(forClass) && forClass != ClassDictInit.class) { @@ -920,6 +919,13 @@ protected abstract boolean getResult(int comparison); } + /** + * Build a map of common Java collection base types (Map, Iterable, etc) that need to be + * injected with Python's equivalent types' builtin methods (__len__, __iter__, iteritems, etc). + * + * @return A map whose key is the base Java collection types and whose entry is a list of + * injected methods. + */ private static Map, PyBuiltinMethod[]> getCollectionProxies() { if (collectionProxies == null) { collectionProxies = Generic.map(); @@ -1005,13 +1011,32 @@ return Py.java2py(asMap().remove(Py.tojava(key, Object.class))); } }; + PyBuiltinMethodNarrow mapIterItemsProxy = new MapMethod("iteritems", 0) { + @Override + public PyObject __call__() { + final Iterator> entrySetIterator = asMap().entrySet().iterator(); + return new PyIterator() { + @Override + public PyObject __iternext__() { + if (entrySetIterator.hasNext()) { + Map.Entry nextEntry = entrySetIterator.next(); + // yield a Python tuple object (key, value) + return new PyTuple(Py.java2py(nextEntry.getKey()), + Py.java2py(nextEntry.getValue())); + } + return null; + } + }; + } + }; collectionProxies.put(Map.class, new PyBuiltinMethod[] {mapLenProxy, // map IterProxy can conflict with Iterable.class; fix after the fact in handleMroError mapIterProxy, mapContainsProxy, mapGetProxy, mapPutProxy, - mapRemoveProxy}); + mapRemoveProxy, + mapIterItemsProxy}); PyBuiltinMethodNarrow listGetProxy = new ListMethod("__getitem__", 1) { @Override