Skip to content

Commit 7a42cfc

Browse files
committed
Support both subclassing from Java in a Python class and a Python implementatin of __tojava__
Required regenerating with src/templates/gderived.py all classes using object.derived in their template. Thanks to Daniel Martin for an initial version of this change. Fixes http://bugs.jython.org/issue1795
1 parent 612a7ac commit 7a42cfc

File tree

152 files changed

+855
-297
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+855
-297
lines changed

ACKNOWLEDGMENTS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Jython in ways large and small, in no particular order:
153153
Eliya Sadan
154154
Stefan Richthofer
155155
Jason Madden
156+
Daniel Martin
156157

157158
Local Variables:
158159
mode: indented-text

Lib/test/test_java_subclasses.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
'''Tests subclassing Java classes in Python'''
22
import os
33
import sys
4+
import threading
45
import unittest
56

67
from test import test_support
78

89
from java.lang import (Boolean, Class, ClassLoader, Comparable,Integer, Object, Runnable, String,
9-
Thread, ThreadGroup, UnsupportedOperationException)
10+
Thread, ThreadGroup, InterruptedException, UnsupportedOperationException)
1011
from java.util import AbstractList, ArrayList, Date, Hashtable, HashSet, Vector
1112
from java.util.concurrent import Callable, Executors
1213

@@ -15,7 +16,9 @@
1516
from javax.swing.table import AbstractTableModel
1617

1718
from org.python.tests import BeanInterface, Callbacker, Coercions, OwnMethodCaller
18-
from javatests import InheritanceA, InheritanceB, InheritanceC, InheritanceD
19+
from javatests import (
20+
InheritanceA, InheritanceB, InheritanceC, InheritanceD,
21+
ExtendedInterface, UseExtendedInterface)
1922

2023

2124
class InterfaceTest(unittest.TestCase):
@@ -555,6 +558,73 @@ def everyOther(self):
555558
self.assertE(e.buildParent(), "D", InheritanceD, E)
556559

557560

561+
class ChooseCorrectToJavaTest(unittest.TestCase):
562+
563+
# Verifies fix for http://bugs.jython.org/issue1795
564+
#
565+
# Note that we use threading.Thread because we have imported
566+
# java.lang.Thread as Thread
567+
568+
def test_extended_thread(self):
569+
570+
class ExtendedThread(threading.Thread, ExtendedInterface):
571+
def returnSomething(self):
572+
return "yo yo yo"
573+
574+
result = [None]
575+
def f(r):
576+
r[0] = 47
577+
578+
t = ExtendedThread(target=f, args=(result,))
579+
self.assertEqual(
580+
UseExtendedInterface().countWords(t),
581+
3)
582+
583+
# Also verify that t still works as a regular thread
584+
t.start()
585+
t.join()
586+
self.assertFalse(t.isAlive())
587+
self.assertEqual(result[0], 47)
588+
589+
def test_interruption(self):
590+
# based on this code http://www.jython.org/jythonbook/en/1.0/Concurrency.html#interruption,
591+
# which demonstrates __tojava__ works properly
592+
593+
class ExtendedThread(threading.Thread, ExtendedInterface):
594+
def returnSomething(self):
595+
return "yo yo yo"
596+
597+
def wait_until_interrupted(cv):
598+
with cv:
599+
while not Thread.currentThread().isInterrupted():
600+
try:
601+
# this condition variable is never notified, so will only
602+
# succeed if interrupted
603+
cv.wait()
604+
except InterruptedException, e:
605+
break
606+
607+
unfair_condition = threading.Condition()
608+
threads = [
609+
ExtendedThread(
610+
name="thread #%d" % i,
611+
target=wait_until_interrupted,
612+
args=(unfair_condition,))
613+
for i in xrange(5)]
614+
615+
for thread in threads:
616+
thread.start()
617+
for thread in threads:
618+
Thread.interrupt(thread)
619+
for thread in threads:
620+
thread.join(5)
621+
622+
# this assertion only succeeds if threads terminated because
623+
# they were interrupted
624+
for thread in threads:
625+
self.assertFalse(thread.isAlive())
626+
627+
558628
def test_main():
559629
test_support.run_unittest(
560630
InterfaceTest,
@@ -566,7 +636,8 @@ def test_main():
566636
MetaClassTest,
567637
AbstractMethodTest,
568638
SuperIsSuperTest,
569-
HierarchyTest)
639+
HierarchyTest,
640+
ChooseCorrectToJavaTest)
570641

571642

572643
if __name__ == '__main__':

src/org/python/antlr/ast/AssertDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/AssignDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/AttributeDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/AugAssignDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/BinOpDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/BoolOpDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/BreakDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

src/org/python/antlr/ast/CallDerived.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,11 @@ public Object __tojava__(Class c) {
11381138
// Otherwise, we call the derived __tojava__, if it exists:
11391139
PyType self_type=getType();
11401140
PyObject impl=self_type.lookup("__tojava__");
1141-
if (impl!=null)
1142-
return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
1141+
if (impl!=null) {
1142+
PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
1143+
if (delegate!=this)
1144+
return delegate.__tojava__(Object.class);
1145+
}
11431146
return super.__tojava__(c);
11441147
}
11451148

0 commit comments

Comments
 (0)