From: <cg...@us...> - 2008-12-05 11:21:59
|
Revision: 5700 http://jython.svn.sourceforge.net/jython/?rev=5700&view=rev Author: cgroves Date: 2008-12-05 11:21:55 +0000 (Fri, 05 Dec 2008) Log Message: ----------- Make methods from superclasses and superinterfaces of private, protected or package protected classes call through their parent versions. Fixes blowups with a package protected implementation of attributes in sax. Modified Paths: -------------- branches/newstyle-java-types/Lib/test/test_java_visibility.py branches/newstyle-java-types/src/org/python/core/PyJavaType.java Added Paths: ----------- branches/newstyle-java-types/tests/java/org/python/tests/InterfaceCombination.java Modified: branches/newstyle-java-types/Lib/test/test_java_visibility.py =================================================================== --- branches/newstyle-java-types/Lib/test/test_java_visibility.py 2008-12-05 09:06:12 UTC (rev 5699) +++ branches/newstyle-java-types/Lib/test/test_java_visibility.py 2008-12-05 11:21:55 UTC (rev 5700) @@ -1,6 +1,6 @@ import unittest from test import test_support -from org.python.tests import Invisible, SubVisible, Visible, VisibleOverride +from org.python.tests import InterfaceCombination, Invisible, SubVisible, Visible, VisibleOverride from org.python.tests import VisibilityResults as Results class VisibilityTest(unittest.TestCase): @@ -67,6 +67,21 @@ self.failUnless('visibleInstance' in c.__dict__, 'visibleInstance expected in %s __dict__' % c) + def test_interface_combination(self): + '''Checks that a private class that extends a public class and public interfaces has only the items + from the public bases visible''' + i = InterfaceCombination.newImplementation() + self.assertEquals(InterfaceCombination.NO_ARG_RESULT, i.getValue(), + "methods from IFace should be visible on Implementation") + self.assertEquals(InterfaceCombination.ONE_ARG_RESULT, i.getValue("one arg"), + "methods from IIFace should be visible on Implementation") + self.assertEquals(InterfaceCombination.TWO_ARG_RESULT, i.getValue("one arg", "two arg"), + "methods from Base should be visible on Implementation") + self.assertRaises(TypeError, i.getValue, "one arg", "two arg", "three arg", + "methods defined solely on Implementation shouldn't be visible") + self.assertFalse(hasattr(i, "internalMethod"), + "methods from private interfaces shouldn't be visible on a private class") + def test_main(): test_support.run_unittest(VisibilityTest) Modified: branches/newstyle-java-types/src/org/python/core/PyJavaType.java =================================================================== --- branches/newstyle-java-types/src/org/python/core/PyJavaType.java 2008-12-05 09:06:12 UTC (rev 5699) +++ branches/newstyle-java-types/src/org/python/core/PyJavaType.java 2008-12-05 11:21:55 UTC (rev 5700) @@ -83,6 +83,7 @@ // org.python.core if (!Modifier.isPublic(underlying_class.getModifiers()) && !name.startsWith("org.python.core")) { + handleSuperMethodArgCollisions(); return; } @@ -308,6 +309,59 @@ } } + /** + * Private, protected or package protected classes that implement public interfaces or extend + * public classes can't have their implementations of the methods of their supertypes called + * through reflection due to Sun VM bug 4071957(http://tinyurl.com/le9vo). They can be called + * through the supertype version of the method though. Unfortunately we can't just let normal + * mro lookup of those methods handle routing the call to the correct version as a class can + * implement interfaces or classes that each have methods with the same name that takes + * different number or types of arguments. Instead this method goes through all interfaces + * implemented by this class, and combines same-named methods into a single PyReflectedFunction. + * + * Prior to Jython 2.5, this was handled in PyJavaClass.setMethods by setting methods in package + * protected classes accessible which made them callable through reflection. That had the + * drawback of failing when running in a security environment that didn't allow setting + * accessibility, so this method replaced it. + */ + private void handleSuperMethodArgCollisions() { + for (Class iface : underlying_class.getInterfaces()) { + for (Method meth : iface.getMethods()) { + String nmethname = normalize(meth.getName()); + PyObject[] where = new PyObject[1]; + PyObject obj = lookup_where(nmethname, where); + if (obj == null) { + // Nothing in our supertype hierarchy defines something with this name, so it + // must not be visible there. + continue; + } else if (where[0] == this) { + // This method is the only thing defining items in this class' dict, so it must + // be a PyReflectedFunction created here. See if it needs the current method + // added to it. + if (!((PyReflectedFunction)obj).handles(meth)) { + ((PyReflectedFunction)obj).addMethod(meth); + } + } else { + // There's something in a superclass with the same name. If this class extends a + // class and doesn't just implement something, the extended class is first in + // mro, so items defined on the extended class will show up here. Thanks to that + // and copying the base function, we can get away with just looping over + // interface methods. + PyReflectedFunction func; + if (obj instanceof PyReflectedFunction) { + func = ((PyReflectedFunction)obj).copy(); + if (!func.handles(meth)) { + func.addMethod(meth); + } + } else { + func = new PyReflectedFunction(meth); + } + dict.__setitem__(nmethname, func); + } + } + } + } + private static boolean declaredOnMember(Class<?> base, Member declaring) { return base == null || (declaring.getDeclaringClass() != base && base.isAssignableFrom(declaring.getDeclaringClass())); Added: branches/newstyle-java-types/tests/java/org/python/tests/InterfaceCombination.java =================================================================== --- branches/newstyle-java-types/tests/java/org/python/tests/InterfaceCombination.java (rev 0) +++ branches/newstyle-java-types/tests/java/org/python/tests/InterfaceCombination.java 2008-12-05 11:21:55 UTC (rev 5700) @@ -0,0 +1,49 @@ +package org.python.tests; + +public class InterfaceCombination { + + public static final String NO_ARG_RESULT = "no_arg_result"; + + public static final String ONE_ARG_RESULT = "one_arg_result"; + + public static final String TWO_ARG_RESULT = "two_arg_result"; + + public interface IFace { + String getValue(); + } + + public interface IIFace { + String getValue(String name); + } + + interface Hidden { + void internalMethod(); + } + + public static class Base { + public String getValue(String one, String two) { + return TWO_ARG_RESULT; + } + } + + private static class Implementation extends Base implements IFace, IIFace, Hidden { + + public String getValue(String one, String two, String three) { + return three; + } + + public String getValue() { + return NO_ARG_RESULT; + } + + public String getValue(String name) { + return ONE_ARG_RESULT; + } + + public void internalMethod() {} + } + + public static Object newImplementation() { + return new Implementation(); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |