Re: [Py4j-users] An issue in reflection?
Status: Beta
Brought to you by:
barthe
From: Jeremy <ken...@gm...> - 2014-05-16 23:35:37
|
Sorry for the delayed reply. Been busy, finally got time to work on my project. I looked at the Vector.java code and can see that it calls the Object class method, equals(). So taking your suggestion, I added an equals(Object) method to the interface (not necessary likely) and tried to implement something in the implementing class in Python. Something like: class equals(self, obj): if self == obj: return True return False But still got the same error. Tried adding in Python's global equal, and that didn't work either. And even tried creating a UUID for each EventListener, but that didn't work either. It just can't seem to find the equals method. My final EventListener ended up looking like this. class EventListener(object): id = uuid.uuid4() def onEvent(self, event): pass def equals(self, obj): return __eq__(obj) def __eq__(self, obj): if obj == None: return False if obj.id == self.id: return True else: return False class Java: implements = ['pctelelog.EventListener'] pass My solution that seems to be working now has been to remove passing around an interface and instead rename the interface EventCallback and wrap it inside a new class (EventListener) and pass an object of that class around. It works fine but I have a strange issue now, maybe I'm doing it wrong. Here's my new EventListener.java public class EventListener implements EventCallback { private EventCallback m_callback = null; public EventListener() { } public EventListener(EventCallback callback) { assert callback != null; m_callback = callback; } public void setCallback(EventCallback callback) { m_callback = callback; } public static EventListener createEventListener(EventCallback callback) { return new EventListener(callback); } @Override public void onEvent(AbstractEvent event) { m_callback.onEvent(event); } } Here's the Python I use to get an instance of the class and then add it to the listener pool: (This method sits inside a PyQt Widget class.) def initCallback(self, func): callback = EventCallback() callback.onEvent = self.onEvent self.eventListener = self.__gateway.jvm.pctelelog.EventListener(callback) self.__gateway.entry_point.addEventListener(self.eventListener) When I try to do it like that I get an error (Logger + Error): Callback Server Starting Socket listening on ('127.0.0.1', 25334) Command to send: r u pctelelog rj e Answer received: yp Command to send: r u pctelelog.EventListener rj e Answer received: ycpctelelog.EventListener Traceback (most recent call last): File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", line 27, in <module> Launcher() File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/Launcher.py", line 23, in __init__ mainWindow = MainWindow(self.__gateway) File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", line 25, in __init__ self.initCallback(self.onEvent) File "/Users/Shared/eclipse/workspace/PCTeleLog-PyQt/pytelelog-pyqt/MainWindow.py", line 49, in initCallback self.eventListener = self.__gateway.jvm.pctelelog.EventListener(callback) File "/usr/local/lib/python2.7/site-packages/py4j/java_gateway.py", line 662, in __call__ args_command = ''.join([get_command_part(arg) for arg in args]) File "/usr/local/lib/python2.7/site-packages/py4j/protocol.py", line 261, in get_command_part command_part = PYTHON_PROXY_TYPE + python_proxy_pool.put(parameter) AttributeError: 'NoneType' object has no attribute 'put' === Now, if I change it around and instantiate with the void constructor and set the callback with the setter. It works fine. def initCallback(self, func): callback = EventCallback() callback.onEvent = self.onEvent self.eventListener = self.__gateway.jvm.pctelelog.EventListener() self.eventListener.setCallback(callback) self.__gateway.entry_point.addEventListener(self.eventListener) I'd rather do without the setter if there was a way to manage it. Any idea what's going on? Thanks! On 5/7/14, 7:54 AM, Barthelemy Dagenais wrote: > Hi! > > Thanks for using Py4J! I'll try to look at this issue more deeply > during the weekend, but from the stack trace, it seems the Java side > is sending a method call to the Python side and the Python side is > replying with an exception: > > Error: > py4j.protocol.Py4JJavaError: An error occurred while calling > t.removeEventListener. > : py4j.Py4JException: An exception was raised by the Python Proxy. > Return Message: x > > Also, from the stack trace, it appears that when deleting the listener > from the Java vector, the vector calls the "equals" method on the > listener. This is the first time I have to deal with this scenario and > I believe the equals method is delegated to the python side. Because > it is not implemented, I believe this may be the cause of failure. A > workaround might be to try to implement an "equals" method in your > Python listener. > > Do you have logging enabled on the Python side? Any stack trace visible there? > > Btw, you should subscribe to the mailing list, it would be easier to > manage the replies :-) > > Bart > > On Tue, May 6, 2014 at 7:58 PM, Jeremy <ken...@gm...> wrote: >> So I'm trying to use Py4j to let a UI talk to a Java server. The java >> server uses 3 threads (entry-point, server socket, client-event >> dispatch). The python UI registers an event call back listener and that >> listener eventually gets dumped into a Vector. I had some initial >> trouble getting the addEventListener() working but fixed it (somehow). >> But now any calls to removeEventListener() don't work. >> >> My first guess was something to do with different instances of the >> object when Vector does the lookup, but I'm not sure. I don't understand >> relfection concepts well enough and the Py->Java (callback) thing seems >> to suggest I should be fine since the original eventlistener hasn't been >> garbage collected yet. If you have any insight that would be great. >> >> Error: >> py4j.protocol.Py4JJavaError: An error occurred while calling >> t.removeEventListener. >> : py4j.Py4JException: An exception was raised by the Python Proxy. >> Return Message: x >> at py4j.Protocol.getReturnValue(Protocol.java:417) >> at >> py4j.reflection.PythonProxyHandler.invoke(PythonProxyHandler.java:113) >> at com.sun.proxy.$Proxy0.equals(Unknown Source) >> at java.util.Vector.indexOf(Vector.java:404) >> at java.util.Vector.indexOf(Vector.java:378) >> at java.util.Vector.removeElement(Vector.java:637) >> at java.util.Vector.remove(Vector.java:795) >> at >> pctelelog.EventOperatorThread.removeEventListener(EventOperatorThread.java:20) >> at pctelelog.ServerThread.removeEventListener(ServerThread.java:16) >> at pctelelog.Launcher.removeEventListener(Launcher.java:17) >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >> at >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) >> >> This code is a stripped down version of the development version but both >> are generating the same error. >> >> package pctelelog; >> >> public class Event { >> public String testData = "test"; >> } >> >> === >> >> package pctelelog; >> >> public interface EventListener { >> public void onEvent(Event event); >> } >> >> === >> >> package pctelelog; >> >> import java.util.Vector; >> >> public class EventOperatorThread extends Thread { >> >> private Vector<EventListener> m_listeners = new >> Vector<EventListener>(); >> >> public void run() { >> while(true) {} >> } >> >> public synchronized void addEventListener(EventListener listener) { >> System.out.println("ADD"); >> m_listeners.add(listener); >> } >> >> public synchronized void removeEventListener(EventListener listener) { >> System.out.println("REMOVE"); >> m_listeners.remove(listener); >> } >> } >> >> === >> >> package pctelelog; >> >> public class ServerThread extends Thread { >> >> private EventOperatorThread m_operator = new EventOperatorThread(); >> >> public void run() { >> m_operator.start(); >> while(true) {} >> } >> >> public synchronized void addEventListener(EventListener listener) { >> m_operator.addEventListener(listener); >> } >> public synchronized void removeEventListener(EventListener listener) { >> m_operator.removeEventListener(listener); >> } >> >> } >> >> === >> >> package pctelelog; >> >> import py4j.GatewayServer; >> >> public class Launcher { >> private ServerThread m_server = new ServerThread(); >> >> public Launcher() { >> m_server.start(); >> System.out.println("Server started."); >> } >> >> public void addEventListener(EventListener listener) { >> m_server.addEventListener(listener); >> } >> public void removeEventListener(EventListener listener) { >> m_server.removeEventListener(listener); >> } >> >> public static void main(String[] args) { >> GatewayServer gateway = new GatewayServer(new Launcher()); >> gateway.start(); >> } >> } >> >> === >> >> from py4j.java_gateway import JavaGateway, GatewayClient >> >> class EventListener(object): >> >> def onEvent(self, event): >> print event.testData; >> >> class Java: >> implements = ['pctelelog.EventListener'] >> >> class Launcher: >> >> def __init__(self): >> self.__gateway = JavaGateway(start_callback_server=True) >> listener = EventListener() >> self.__gateway.entry_point.addEventListener(listener) >> self.__gateway.entry_point.removeEventListener(listener) >> >> if __name__ == '__main__': >> Launcher() >> pass >> >> >> ------------------------------------------------------------------------------ >> Is your legacy SCM system holding you back? Join Perforce May 7 to find out: >> • 3 signs your SCM is hindering your productivity >> • Requirements for releasing software faster >> • Expert tips and advice for migrating your SCM now >> http://p.sf.net/sfu/perforce >> _______________________________________________ >> Py4j-users mailing list >> Py4...@li... >> https://lists.sourceforge.net/lists/listinfo/py4j-users |