From: <cg...@us...> - 2009-01-26 02:21:09
|
Revision: 5981 http://jython.svn.sourceforge.net/jython/?rev=5981&view=rev Author: cgroves Date: 2009-01-26 02:21:05 +0000 (Mon, 26 Jan 2009) Log Message: ----------- Defer resolving inner classes till the containing class is fully resolved. Fixes issue #1234. Modified Paths: -------------- trunk/jython/Lib/test/test_import_jy.py trunk/jython/src/org/python/core/PyJavaType.java trunk/jython/src/org/python/core/PyType.java Added Paths: ----------- trunk/jython/tests/java/org/python/tests/inbred/ trunk/jython/tests/java/org/python/tests/inbred/Metis.java trunk/jython/tests/java/org/python/tests/inbred/Zeus.java Modified: trunk/jython/Lib/test/test_import_jy.py =================================================================== --- trunk/jython/Lib/test/test_import_jy.py 2009-01-26 01:19:12 UTC (rev 5980) +++ trunk/jython/Lib/test/test_import_jy.py 2009-01-26 02:21:05 UTC (rev 5981) @@ -153,6 +153,11 @@ self.assertEquals(subprocess.call([sys.executable, test_support.findfile("import_star_from_java.py")]), 0) + def test_selfreferential_classes(self): + from org.python.tests.inbred import Metis + from org.python.tests.inbred import Zeus + self.assertEquals(Metis, Zeus.Athena.__bases__[0]) + self.assertEquals(Zeus, Metis.__bases__[0]) def test_main(): test_support.run_unittest(MislabeledImportTestCase, Modified: trunk/jython/src/org/python/core/PyJavaType.java =================================================================== --- trunk/jython/src/org/python/core/PyJavaType.java 2009-01-26 01:19:12 UTC (rev 5980) +++ trunk/jython/src/org/python/core/PyJavaType.java 2009-01-26 02:21:05 UTC (rev 5981) @@ -15,8 +15,6 @@ import java.util.Set; import org.python.core.util.StringUtil; -import org.python.expose.ExposeAsSuperclass; -import org.python.expose.ExposedType; import org.python.util.Generic; public class PyJavaType extends PyType { @@ -164,8 +162,9 @@ } computeMro(toMerge, mro); } + @Override - protected void init(Class<?> forClass) { + protected void init(Class<?> forClass, Set<PyJavaType> needsInners) { name = forClass.getName(); // Strip the java fully qualified class name from Py classes in core if (name.startsWith("org.python.core.Py")) { @@ -179,8 +178,9 @@ underlying_class = forClass; computeLinearMro(baseClass); } else { + needsInners.add(this); javaProxy = forClass; - objtype = PyType.fromClass(Class.class); + objtype = PyType.fromClassSkippingInners(Class.class, needsInners); // Wrapped Java types fill in their mro first using all of their interfaces then their // super class. List<PyObject> visibleBases = Generic.list(); @@ -191,16 +191,16 @@ // mro continue; } - visibleBases.add(PyType.fromClass(iface)); + visibleBases.add(PyType.fromClassSkippingInners(iface, needsInners)); } if (javaProxy == Object.class) { - base = PyType.fromClass(PyObject.class); + base = PyType.fromClassSkippingInners(PyObject.class, needsInners); } else if(baseClass == null) { - base = PyType.fromClass(Object.class); + base = PyType.fromClassSkippingInners(Object.class, needsInners); }else if (javaProxy == Class.class) { - base = PyType.fromClass(PyType.class); + base = PyType.fromClassSkippingInners(PyType.class, needsInners); } else { - base = PyType.fromClass(baseClass); + base = PyType.fromClassSkippingInners(baseClass, needsInners); } visibleBases.add(base); this.bases = visibleBases.toArray(new PyObject[visibleBases.size()]); @@ -449,21 +449,6 @@ } else { dict.__setitem__("__init__", reflctr); } - for (Class<?> inner : forClass.getClasses()) { - // Only add the class if there isn't something else with that name and it came from this - // class - if (inner.getDeclaringClass() == forClass && - dict.__finditem__(inner.getSimpleName()) == null) { - // If this class is currently being loaded, any exposed types it contains won't have - // set their builder in PyType yet, so add them to BOOTSTRAP_TYPES so they're - // created as PyType instead of PyJavaType - if (inner.getAnnotation(ExposedType.class) != null - || ExposeAsSuperclass.class.isAssignableFrom(inner)) { - Py.BOOTSTRAP_TYPES.add(inner); - } - dict.__setitem__(inner.getSimpleName(), PyType.fromClass(inner)); - } - } for (Map.Entry<Class<?>, PyBuiltinMethod[]> entry : getCollectionProxies().entrySet()) { if (entry.getKey() == forClass) { for (PyBuiltinMethod meth : entry.getValue()) { Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2009-01-26 01:19:12 UTC (rev 5980) +++ trunk/jython/src/org/python/core/PyType.java 2009-01-26 02:21:05 UTC (rev 5981) @@ -357,7 +357,7 @@ * Called on builtin types for a particular class. Should fill in dict, name, mro, base and * bases from the class. */ - protected void init(Class<?> forClass) { + protected void init(Class<?> forClass, Set<PyJavaType> needsInners) { underlying_class = forClass; if (underlying_class == PyObject.class) { mro = new PyType[] {this}; @@ -939,24 +939,24 @@ } // The types in Py.BOOTSTRAP_TYPES are initialized before their builders are assigned, // so do the work of addFromClass & fillFromClass after the fact - fromClass(builder.getTypeClass()).init(builder.getTypeClass()); + fromClass(builder.getTypeClass()).init(builder.getTypeClass(), null); } } - private static PyType addFromClass(Class<?> c) { + private static PyType addFromClass(Class<?> c, Set<PyJavaType> needsInners) { if (ExposeAsSuperclass.class.isAssignableFrom(c)) { PyType exposedAs = fromClass(c.getSuperclass()); class_to_type.put(c, exposedAs); return exposedAs; } - return createType(c); + return createType(c, needsInners); } private static TypeBuilder getBuilder(Class<?> c) { return classToBuilder == null ? null : classToBuilder.get(c); } - private static PyType createType(Class<?> c) { + private static PyType createType(Class<?> c, Set<PyJavaType> needsInners) { PyType newtype; if (c == PyType.class) { newtype = new PyType(false); @@ -975,22 +975,56 @@ class_to_type.put(c, newtype); newtype.builtin = true; - newtype.init(c); + newtype.init(c,needsInners); return newtype; } public static synchronized PyType fromClass(Class<?> c) { if (class_to_type == null) { class_to_type = Generic.map(); - addFromClass(PyType.class); + addFromClass(PyType.class, null); } PyType type = class_to_type.get(c); if (type != null) { return type; } - return addFromClass(c); + // We haven't seen this class before, so it's type needs to be created. If it's being + // exposed as a Java class, defer processing its inner types until it's completely + // created in case the inner class references a class that references this class. + Set<PyJavaType> needsInners = Generic.set(); + PyType result = addFromClass(c, needsInners); + for (PyJavaType javaType : needsInners) { + Class<?> forClass = javaType.getProxyType(); + if (forClass == null) { + continue; + } + for (Class<?> inner : forClass.getClasses()) { + // Only add the class if there isn't something else with that name and it came from this + // class + if (inner.getDeclaringClass() == forClass && + javaType.dict.__finditem__(inner.getSimpleName()) == null) { + // If this class is currently being loaded, any exposed types it contains won't have + // set their builder in PyType yet, so add them to BOOTSTRAP_TYPES so they're + // created as PyType instead of PyJavaType + if (inner.getAnnotation(ExposedType.class) != null + || ExposeAsSuperclass.class.isAssignableFrom(inner)) { + Py.BOOTSTRAP_TYPES.add(inner); + } + javaType.dict.__setitem__(inner.getSimpleName(), PyType.fromClass(inner)); + } + } + } + return result; } + static PyType fromClassSkippingInners(Class<?> c, Set<PyJavaType> needsInners) { + PyType type = class_to_type.get(c); + if (type != null) { + return type; + } + return addFromClass(c, needsInners); + } + @ExposedMethod(doc = BuiltinDocs.type___getattribute___doc) final PyObject type___getattribute__(PyObject name) { String n = asName(name); Added: trunk/jython/tests/java/org/python/tests/inbred/Metis.java =================================================================== --- trunk/jython/tests/java/org/python/tests/inbred/Metis.java (rev 0) +++ trunk/jython/tests/java/org/python/tests/inbred/Metis.java 2009-01-26 02:21:05 UTC (rev 5981) @@ -0,0 +1,3 @@ +package org.python.tests.inbred; + +public interface Metis extends Zeus {} Added: trunk/jython/tests/java/org/python/tests/inbred/Zeus.java =================================================================== --- trunk/jython/tests/java/org/python/tests/inbred/Zeus.java (rev 0) +++ trunk/jython/tests/java/org/python/tests/inbred/Zeus.java 2009-01-26 02:21:05 UTC (rev 5981) @@ -0,0 +1,11 @@ +package org.python.tests.inbred; + +/** + * Zeus ate Metis to prevent her from giving birth, but Athena was born inside Zeus' head anyway. By + * the mythology Metis should extend from Oceanus and Tethys, but we need Metis to extend Zeus to + * get the kind of inheritance that caused http://bugs.jython.org/issue1234 + */ +public interface Zeus { + + public interface Athena extends Metis {} +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |