0

新しいおもちゃの JCC 2.21 をいじっていますが、Python スクリプトでコールバックを実装するのに問題があります。次の単純な Java スレッド API をラップし、python 2.7 (CPython) から呼び出していますが、JccTest.addJccTestListener(JccTestListener)メソッドを呼び出すと、JVM は null 引数を報告します。

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):

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)

null リスナー インスタンス以外に、このようなことは CPython でも可能ですか? その実装では、一度に 1 つのスレッドしか Python スクリプトを実行できないと読んだことがありますが、これは (?) 問題になる可能性があります。Jython でこのようなことを行うのは簡単なことでした。

私はPythonにはかなり慣れていないので、優しくしてください。

4

1 に答える 1

0

理解した。これを機能させるには、Java クラスの Pythonic 拡張を定義する必要があります。詳細な手順はJCC ドキュメント( Python での Java クラス拡張の記述 ) に記載されており、かなり単純です。

最初に、インターフェースを実装するクラスをコーディングし、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);

}

マーカーは私のコメントで示され、python で拡張されるすべてのクラスで逐語的に表示される必要があります。私の実装では、インターフェイス メソッドをネイティブ実装メソッドに委任します。これは Python で拡張されます。

次に、通常どおりラッパーを生成します。

python -m jcc --jar jcc-test.jar --python jcc_test --build --install

最後に、新しいクラスの 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
于 2015-01-14T09:53:36.737 に答える