PyLucene JCC:在python中实现一个Java接口,并通过它接收Java线程回调
PyLucene JCC: implement a Java interface in python and receive Java thread callbacks through it
我正在玩我的新玩具 JCC 2.21,但在 python 脚本中实现回调时遇到了问题。我包装了以下简单的 Java 线程 API 并从 python 2.7 (CPython) 调用它,但是当我调用 JccTest.addJccTestListener(JccTestListener)
方法时,JVM 报告一个空参数.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class JccTest implements Runnable {
private final Object listenersLock = new Object();
private final List<JccTestListener> listeners = new ArrayList<JccTestListener>();
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean finished = new AtomicBoolean(false);
public void start() {
if (running.compareAndSet(false, true)) {
new Thread(this).start();
}
}
public void stop() {
finished.set(true);
}
public void addJccTestListener(JccTestListener l) {
if (l == null) {
throw new IllegalArgumentException("argument must be non-null");
}
synchronized (listenersLock) {
listeners.add(l);
}
}
public void removeJccTestListener(JccTestListener l) {
synchronized (listenersLock) {
listeners.remove(l);
}
}
@Override
public void run() {
System.out.println("Start");
while (!finished.get()) {
System.out.println("Notifiying listeners");
synchronized (listenersLock) {
for (JccTestListener l : listeners) {
System.out.println("Notifiying " + String.valueOf(l));
l.message("I'm giving you a message!");
}
}
System.out.println("Sleeping");
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
continue;
}
}
running.set(false);
System.out.println("Stop");
}
public static void main(String[] args) throws InterruptedException {
JccTest test = new JccTest();
test.addJccTestListener(new JccTestListener() {
@Override
public void message(String msg) {
// called from another thread
System.out.println(msg);
}
});
test.start();
Thread.sleep(10000);
test.stop();
}
}
public interface JccTestListener {
public void message(String msg);
}
生成的包装器:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
然后执行这个脚本(相当于JccTest
的main方法):
import jcc_test
import time, sys
jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListener):
def __init__(self):
pass
def message(self, msg):
print msg
test.addJccTestListener(MyListener())
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
这导致:
"python.exe" jcc_test_test.py
Traceback (most recent call last):
File "jcc_test_test.py", line 16, in <module>
test.addJccTestListener(MyListener())
jcc_test.JavaError: java.lang.IllegalArgumentException: argument must be non-null
Java stacktrace:
java.lang.IllegalArgumentException: argument must be non-null
at com.example.jcc.JccTest.addJccTestListener(JccTest.java:32)
除了空侦听器实例之外,CPython 甚至可以做这样的事情吗?我读过,在它的实现中,一次只能有一个线程执行 python 脚本,这对我来说可能(?)是个问题。用 Jython 做这样的事情是微不足道的。
我对 python 比较陌生,所以请保持温柔。
想通了。您需要为 java class 定义一个 pythonic 扩展名才能使其工作。详细过程在JCC documentation(Writing Java class extensions in Python)中描述,相当简单。
首先,编写实现您的界面的 class 代码,并添加一些 JCC 可识别并影响包装器生成器将生成的内容的魔法标记。
public class JccTestListenerImpl implements JccTestListener {
// jcc specific
private long pythonObject;
public JccTestListenerImpl() {}
@Override
public void message(String msg) {
messageImpl(msg);
}
// jcc specific
public void pythonExtension(long pythonObject) {
this.pythonObject = pythonObject;
}
// jcc specific
public long pythonExtension() {
return this.pythonObject;
}
// jcc specific
@Override
public void finalize() throws Throwable {
pythonDecRef();
}
// jcc specific
public native void pythonDecRef();
public native void messageImpl(String msg);
}
标记由我的评论表示,并且必须逐字出现在任何 class 中,要在 python 中扩展。我的实现是将接口方法委托给一个原生的实现方法,在python.
中进行扩展
然后照常生成包装器:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
最后为新 class 做一个 python 扩展:
import jcc_test
import time, sys
jvm = jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListenerImpl):
## if you define a constructor here make sure to invoke super constructor
#def __init__(self):
# super(MyListener, self).__init__()
# pass
def messageImpl(self, msg):
print msg
listener = MyListener()
test.addJccTestListener(listener)
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
随着回调的到来,这现在可以正常工作了。
"python.exe" jcc_test_test.py
Start
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl@4b67cf4d
I'm giving you a message!
Sleeping
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl@4b67cf4d
I'm giving you a message!
Sleeping
Process finished with exit code 0
我正在玩我的新玩具 JCC 2.21,但在 python 脚本中实现回调时遇到了问题。我包装了以下简单的 Java 线程 API 并从 python 2.7 (CPython) 调用它,但是当我调用 JccTest.addJccTestListener(JccTestListener)
方法时,JVM 报告一个空参数.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class JccTest implements Runnable {
private final Object listenersLock = new Object();
private final List<JccTestListener> listeners = new ArrayList<JccTestListener>();
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean finished = new AtomicBoolean(false);
public void start() {
if (running.compareAndSet(false, true)) {
new Thread(this).start();
}
}
public void stop() {
finished.set(true);
}
public void addJccTestListener(JccTestListener l) {
if (l == null) {
throw new IllegalArgumentException("argument must be non-null");
}
synchronized (listenersLock) {
listeners.add(l);
}
}
public void removeJccTestListener(JccTestListener l) {
synchronized (listenersLock) {
listeners.remove(l);
}
}
@Override
public void run() {
System.out.println("Start");
while (!finished.get()) {
System.out.println("Notifiying listeners");
synchronized (listenersLock) {
for (JccTestListener l : listeners) {
System.out.println("Notifiying " + String.valueOf(l));
l.message("I'm giving you a message!");
}
}
System.out.println("Sleeping");
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
continue;
}
}
running.set(false);
System.out.println("Stop");
}
public static void main(String[] args) throws InterruptedException {
JccTest test = new JccTest();
test.addJccTestListener(new JccTestListener() {
@Override
public void message(String msg) {
// called from another thread
System.out.println(msg);
}
});
test.start();
Thread.sleep(10000);
test.stop();
}
}
public interface JccTestListener {
public void message(String msg);
}
生成的包装器:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
然后执行这个脚本(相当于JccTest
的main方法):
import jcc_test
import time, sys
jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListener):
def __init__(self):
pass
def message(self, msg):
print msg
test.addJccTestListener(MyListener())
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
这导致:
"python.exe" jcc_test_test.py
Traceback (most recent call last):
File "jcc_test_test.py", line 16, in <module>
test.addJccTestListener(MyListener())
jcc_test.JavaError: java.lang.IllegalArgumentException: argument must be non-null
Java stacktrace:
java.lang.IllegalArgumentException: argument must be non-null
at com.example.jcc.JccTest.addJccTestListener(JccTest.java:32)
除了空侦听器实例之外,CPython 甚至可以做这样的事情吗?我读过,在它的实现中,一次只能有一个线程执行 python 脚本,这对我来说可能(?)是个问题。用 Jython 做这样的事情是微不足道的。
我对 python 比较陌生,所以请保持温柔。
想通了。您需要为 java class 定义一个 pythonic 扩展名才能使其工作。详细过程在JCC documentation(Writing Java class extensions in Python)中描述,相当简单。
首先,编写实现您的界面的 class 代码,并添加一些 JCC 可识别并影响包装器生成器将生成的内容的魔法标记。
public class JccTestListenerImpl implements JccTestListener {
// jcc specific
private long pythonObject;
public JccTestListenerImpl() {}
@Override
public void message(String msg) {
messageImpl(msg);
}
// jcc specific
public void pythonExtension(long pythonObject) {
this.pythonObject = pythonObject;
}
// jcc specific
public long pythonExtension() {
return this.pythonObject;
}
// jcc specific
@Override
public void finalize() throws Throwable {
pythonDecRef();
}
// jcc specific
public native void pythonDecRef();
public native void messageImpl(String msg);
}
标记由我的评论表示,并且必须逐字出现在任何 class 中,要在 python 中扩展。我的实现是将接口方法委托给一个原生的实现方法,在python.
中进行扩展然后照常生成包装器:
python -m jcc --jar jcc-test.jar --python jcc_test --build --install
最后为新 class 做一个 python 扩展:
import jcc_test
import time, sys
jvm = jcc_test.initVM(jcc_test.CLASSPATH)
test = jcc_test.JccTest()
class MyListener(jcc_test.JccTestListenerImpl):
## if you define a constructor here make sure to invoke super constructor
#def __init__(self):
# super(MyListener, self).__init__()
# pass
def messageImpl(self, msg):
print msg
listener = MyListener()
test.addJccTestListener(listener)
test.start()
time.sleep(10)
test.stop()
sys.exit(0)
随着回调的到来,这现在可以正常工作了。
"python.exe" jcc_test_test.py
Start
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl@4b67cf4d
I'm giving you a message!
Sleeping
Notifiying listeners
Notifiying com.example.jcc.JccTestListenerImpl@4b67cf4d
I'm giving you a message!
Sleeping
Process finished with exit code 0