From: <zy...@us...> - 2010-08-10 02:53:26
|
Revision: 7089 http://jython.svn.sourceforge.net/jython/?rev=7089&view=rev Author: zyasoft Date: 2010-08-10 02:53:20 +0000 (Tue, 10 Aug 2010) Log Message: ----------- Support copy.copy (through __copy__) of well-known immutable Java types (drawn from java.lang, java.net, java.util). This better matches the copy semantics of Python than Object#clone/Cloneable. Modified Paths: -------------- trunk/jython/Lib/test/test_java_integration.py trunk/jython/src/org/python/core/PyJavaType.java Modified: trunk/jython/Lib/test/test_java_integration.py =================================================================== --- trunk/jython/Lib/test/test_java_integration.py 2010-08-09 21:24:20 UTC (rev 7088) +++ trunk/jython/Lib/test/test_java_integration.py 2010-08-10 02:53:20 UTC (rev 7089) @@ -561,7 +561,17 @@ copy_bdfl = copy.deepcopy(bdfl) self.assertEqual(str(bdfl), str(copy_bdfl)) + def test_immutable(self): + abc = String("abc") + abc_copy = copy.copy(abc) + self.assertEqual(id(abc), id(abc_copy)) + + fruits = ArrayList([String("apple"), String("banana")]) + fruits_copy = copy.copy(fruits) + self.assertEqual(fruits, fruits_copy) + self.assertNotEqual(id(fruits), id(fruits_copy)) + class UnicodeTest(unittest.TestCase): def test_unicode_conversion(self): Modified: trunk/jython/src/org/python/core/PyJavaType.java =================================================================== --- trunk/jython/src/org/python/core/PyJavaType.java 2010-08-09 21:24:20 UTC (rev 7088) +++ trunk/jython/src/org/python/core/PyJavaType.java 2010-08-10 02:53:20 UTC (rev 7089) @@ -43,6 +43,29 @@ "bounds", "enable"); + + // Add well-known immutable classes from standard packages of + // java.lang, java.net, java.util that are not marked Cloneable. + // This was found by hand, there are likely more! + private final static Set<Class<?>> immutableClasses = Generic.set( + Boolean.class, + Byte.class, + Character.class, + Class.class, + Double.class, + Float.class, + Integer.class, + Long.class, + Short.class, + String.class, + java.net.InetAddress.class, + java.net.Inet4Address.class, + java.net.Inet6Address.class, + java.net.InetSocketAddress.class, + java.net.Proxy.class, + java.net.URI.class, + java.util.concurrent.TimeUnit.class); + private static Map<Class<?>, PyBuiltinMethod[]> collectionProxies; /** @@ -143,15 +166,15 @@ } Set<String> allModified = Generic.set(); - PyJavaType[] conflicted = inConflict.toArray(new PyJavaType[inConflict.size()]); - for (PyJavaType type : conflicted) { + PyJavaType[] conflictedAttributes = inConflict.toArray(new PyJavaType[inConflict.size()]); + for (PyJavaType type : conflictedAttributes) { if (type.modified == null) { continue; } for (String method : type.modified) { if (!allModified.add(method)) { // Another type in conflict has this method, fail PyList types = new PyList(); - for (PyJavaType othertype : conflicted) { + for (PyJavaType othertype : conflictedAttributes) { if (othertype.modified != null && othertype.modified.contains(method)) { types.add(othertype); } @@ -164,7 +187,7 @@ // We can keep trucking, there aren't any existing method name conflicts. Mark the // conflicts in all the classes so further method additions can check for trouble - for (PyJavaType type : conflicted) { + for (PyJavaType type : conflictedAttributes) { for (PyJavaType otherType : inConflict) { if (otherType != type) { if (type.conflicted == null) { @@ -306,23 +329,23 @@ } // Now check if it's a bean property accessor - String name = null; + String beanPropertyName = null; boolean get = true; if (methname.startsWith("get") && methname.length() > 3 && n == 0) { - name = methname.substring(3); + beanPropertyName = methname.substring(3); } else if (methname.startsWith("is") && methname.length() > 2 && n == 0 && meth.getReturnType() == Boolean.TYPE) { - name = methname.substring(2); + beanPropertyName = methname.substring(2); } else if (methname.startsWith("set") && methname.length() > 3 && n == 1) { - name = methname.substring(3); + beanPropertyName = methname.substring(3); get = false; } - if (name != null) { - name = normalize(StringUtil.decapitalize(name)); - PyBeanProperty prop = props.get(name); + if (beanPropertyName != null) { + beanPropertyName = normalize(StringUtil.decapitalize(beanPropertyName)); + PyBeanProperty prop = props.get(beanPropertyName); if (prop == null) { - prop = new PyBeanProperty(name, null, null, null); - props.put(name, prop); + prop = new PyBeanProperty(beanPropertyName, null, null, null); + props.put(beanPropertyName, prop); } if (get) { prop.getMethod = meth; @@ -405,11 +428,11 @@ } for (Method meth : ev.eventClass.getMethods()) { - String name = meth.getName().intern(); - if (dict.__finditem__(name) != null) { + String methodName = meth.getName().intern(); + if (dict.__finditem__(methodName) != null) { continue; } - dict.__setitem__(name, new PyBeanEventProperty(name, + dict.__setitem__(methodName, new PyBeanEventProperty(methodName, ev.eventClass, ev.addMethod, meth)); @@ -607,9 +630,19 @@ }); } - // TODO consider adding support for __copy__ of immutable Java objects - // (__deepcopy__ just works for these objects since it uses serialization instead) + if (immutableClasses.contains(forClass)) { + + // __deepcopy__ just works for these objects since it uses serialization instead + + addMethod(new PyBuiltinMethodNarrow("__copy__") { + @Override + public PyObject __call__() { + return self; + } + }); + } + if(forClass == Cloneable.class) { addMethod(new PyBuiltinMethodNarrow("__copy__") { @Override @@ -881,6 +914,7 @@ collectionProxies = Generic.map(); PyBuiltinMethodNarrow iterableProxy = new PyBuiltinMethodNarrow("__iter__") { + @Override public PyObject __call__() { return new IteratorIter(((Iterable)self.getJavaProxy())); } @@ -906,6 +940,7 @@ containsProxy}); PyBuiltinMethodNarrow iteratorProxy = new PyBuiltinMethodNarrow("__iter__") { + @Override public PyObject __call__() { return new IteratorIter(((Iterator)self.getJavaProxy())); } @@ -913,6 +948,7 @@ collectionProxies.put(Iterator.class, new PyBuiltinMethod[] {iteratorProxy}); PyBuiltinMethodNarrow enumerationProxy = new PyBuiltinMethodNarrow("__iter__") { + @Override public PyObject __call__() { return new EnumerationIter(((Enumeration)self.getJavaProxy())); } @@ -933,6 +969,7 @@ } }; PyBuiltinMethodNarrow mapContainsProxy = new MapMethod("__contains__", 1) { + @Override public PyObject __call__(PyObject obj) { Object other = obj.__tojava__(Object.class); return asMap().containsKey(other) ? Py.True : Py.False; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |