31

JNI(Java Native Interface)に関連するほとんどのドキュメントまたはヘルパーライブラリは、Javaからのネイティブコードの呼び出しに関係しているようです。それ以上の能力があるにもかかわらず、これが主な用途のようです。

私は主に反対の方向で作業したいと思います。既存の(かなり大きな)ポータブルC ++プログラムに、いくつかのJavaライブラリを追加して変更します。たとえば、JDBCを介してデータベースを呼び出したり、JMSを介してメッセージキューシステムを呼び出したり、電子メールを送信したり、独自のJavaクラスを呼び出したりしたいのですが、生のJNIでは、これはかなり不快でエラーが発生しやすくなります。

したがって、理想的には、C ++/CLIがCLRクラスを呼び出すのと同じくらい簡単にJavaクラスを呼び出すことができるC++コードを記述したいと思います。何かのようなもの:

using namespace java::util::regex; // namespaces mapped

Pattern p = Pattern.compile("[,\\s]+");

array<java::lang::String> result = 
    p.split("one,two, three   four ,  five");

for (int i=0; i < result.length(); i++)
    std::cout << result[i] << std::endl;

このように、名前と奇妙な署名文字列を渡すことによってメソッドIDを取得する作業を手動で行う必要がなく、メソッドを呼び出すためのチェックされていないAPIによって引き起こされるプログラミングエラーから保護されます。実際、同等のJavaによく似ています。

NB。私はまだJNIの使用について話し合っています!基盤となるテクノロジーとして、それは私のニーズに最適です。それは「進行中」であり、非常に効率的です。別のプロセスでJavaを実行して、RPC呼び出しを行いたくありません。JNI自体は問題ありません。私はそれに快適なインターフェースが欲しいだけです。

私が指定する一連のJavaクラスによって公開されるものと完全に一致するように、同等のC ++クラス、名前空間、メソッドなどを作成するためのコード生成ツールが必要になります。生成されたC++クラスは次のようになります。

  • 同様にラップされたバージョンのパラメーターを受け入れるメンバー関数を用意し、必要なJNIブードゥーを実行して呼び出しを行います。
  • 自然な方法で呼び出しを連鎖できるように、同じ方法で戻り値をラップします。
  • メソッドIDのクラスごとの静的キャッシュを維持して、毎回検索しないようにします。
  • 完全にスレッドセーフで、ポータブルで、オープンソースであること。
  • すべてのメソッド呼び出しの後に例外を自動的にチェックし、stdC++例外を生成します。
  • また、通常のJNIの方法でネイティブメソッドを記述しているが、他のJavaコードを呼び出す必要がある場合にも機能します。
  • 配列は、プリミティブ型とクラスの間で完全に一貫して機能する必要があります。
  • ローカル参照フレームの外で存続する必要がある場合に参照をラップするためにグローバルのようなものが必要になることは間違いありません-繰り返しますが、すべての配列/オブジェクト参照で同じように機能するはずです。

そのような無料のオープンソースのポータブルライブラリ/ツールは存在しますか、それとも私は夢を見ていますか?

注:私はこの既存の質問を見つけましたが、その場合のOPは、私がしているほど完璧を要求するものではありませんでした...

更新: SWIGについてのコメントは、この前の質問に私を導きました。これは、それがほとんど反対方向についてであり、したがって私が望むことをしないことを示しているようです。

重要

  • これは、Javaクラスとオブジェクトを操作するC ++コードを記述できることについてであり、その逆ではありません(タイトルを参照してください)。
  • JNIが存在することはすでに知っています(質問を参照してください)。しかし、JNI APIへの手書きのコードは、不必要に冗長で、反復的で、エラーが発生しやすく、コンパイル時に型チェックされません。メソッドIDとクラスをキャッシュする場合オブジェクトそれはさらに冗長です。これらすべてを処理するC++ラッパークラスを自動的に生成したいと思います。

更新:私は自分の解決策に取り組み始めました:

https://github.com/danielearwicker/cppjvm

これがすでに存在する場合は、私に知らせてください!

NB。自分のプロジェクトでこれを使用することを検討している場合は、遠慮なく言ってください。ただし、現在、コードは数時間前のものであり、これまでに作成したテストは3つだけです。

4

9 に答える 9

17

はい、まさにこれを行う既存のツールがあります-JavaクラスのC++ラッパーを生成します。これにより、C++でのJavaAPIの使用がより透過的で楽しいものになり、コストとリスクが低くなります。

私が最もよく使用したのはJunC++ionです。成熟していて、パワフルで安定しています。筆頭著者はとても親切で、とても反応がいいです。残念ながら、それは商用製品であり、高価です。

Jaceは、BSDライセンスを持つ無料のオープンソースツールです。私が最後にジェイスと遊んでから何年も経ちました。まだ活発な開発が行われているようです。(10年以上前に、基本的にあなたが尋ねているのと同じ質問をした、元の作者によるUSENETの投稿を今でも覚えています。)

JavaからC++へのコールバックをサポートする必要がある場合は、Javaインターフェースを実装するC++クラスを定義すると便利です。少なくともJunC++ionを使用すると、そのようなC++クラスをコールバックを受け取るJavaメソッドに渡すことができます。前回jaceを試したときは、これをサポートしていませんでしたが、それは7年前のことです。

于 2011-09-27T21:03:04.233 に答える
8

私は、JunC++ionを含むCodemeshの言語統合製品の主要なアーキテクトの1人です。私たちは1999年からこの種の統合を行っており、それは非常にうまく機能しています。最大の問題はJNIの部分ではありません。JNIは面倒でデバッグが困難ですが、正しく理解すれば、ほとんどの場合、機能し続けます。時々、JVMまたはOSの更新によって壊れて、製品を微調整する必要がありますが、一般的には安定しています。

最大の問題は、型システムのマッピングと、一般的なユーザビリティとターゲットソリューションの間のトレードオフです。たとえば、JACEがすべてのオブジェクト参照をグローバルとして扱うという事実が気に入らないと述べています。同じことを(いくつかのエスケープハッチを使用して)行います。これは、パフォーマンスに悪影響を与える場合でも、95%の顧客に最適な動作であることが判明したためです。APIまたは製品を公開する場合は、ほとんどの人が機能するようにするデフォルトを選択する必要があります。ますます多くの人々がマルチスレッドアプリケーションを作成し、他の言語から使用したい多くのJava APIが本質的に非同期コールバックなどでマルチスレッド化されているため、デフォルトオプションとしてローカル参照を選択するのは間違っています。

また、統合仕様を作成するためのGUIベースのコードジェネレーターを人々に提供したいということもわかりました。彼らがそれを指定したら、CLIバージョンを使用してそれをナイトリービルドに統合します。

あなたのプロジェクトで頑張ってください。正しくするのは大変な作業です。私たちはそれに数年を費やしましたが、それでも定期的に改善を続けています。

于 2011-09-28T14:25:11.840 に答える
4

私はほとんど同じ問題を抱えていて、結局自分でそれをすることになりました、多分これは誰かを助けます。

https://github.com/mo22/jnipp

実行時のフットプリントが小さく(<30kb)、参照を管理し、Javaクラスインターフェイスの生成をサポートします。つまり、LocalRef> stringArray; 次に、stringArray [1]-> getBytes()などを使用します。

于 2015-05-05T21:03:43.617 に答える
2

C++からJavaを再呼び出しします。

あなたはあなたが望むことをすることができますが、あなたはJavaを制御させなければなりません。これが意味するのは、ネイティブコードを呼び出すJavaスレッドを作成し、そこからブロックして、ネイティブコードが何かを実行するのを待つということです。十分な作業/スループットを実行するために必要な数のJavaスレッドを作成します。

したがって、C ++アプリケーションが起動し、JVM / JavaVMが作成され(文書化された方法に従って、例はqtjambiコードベースに存在します。以下を参照)、これにより通常のJNI初期化とSystem.loadLibrary()が実行され、JARに「ネイティブ」が提供されます。リンケージ。次に、一連のスレッドを初期化し、(作成した)JNIコードを呼び出します。ここで、C ++コードが実行する作業を提供するのを待って、スレッドをブロックできます。

次に、C ++コード(おそらく別のスレッドから)がセットアップされ、必要なすべての情報がブロックされ待機しているJavaスレッドワーカーの1つに渡され、実行命令が出され、純粋なJavaコードに戻って実行されます。作業して結果を返します。

..。

C ++コードからJavaVMインスタンスをセットアップ、作成、および含めることができます。これを強制的に独自のCLASSPATH/JARにフィードして、C++プログラム内にカプセル化する必要のある包含環境をセットアップできます。

すでにhttp://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.htmlで見つけていると確信しているので、その概要

..。

QtJambiプロジェクトには一種のC++=> Java JNIジェネレーターがあります(私はこれに取り組んでおり、保守を支援しています)。これはQtツールキット用に特別に作成されたものですが、基本的には、C++ヘッダーファイルの束をC++ .cpp /.hファイルと*.javaファイルのコレクションに変換して、オブジェクトのリンケージとシェルインクルージョンを提供し、競合するメモリ割り当てスキームを実現します。一緒によく遊ぶ。多分これから取られるべき何かがあります。

これは確かに、ジェネレーターにたまたまqtjambiプロジェクトに含まれていることを要求していることの証拠であり(ただし、いくつかの作業で独立させることができます)、これはLGPLライセンス(オープンソース)です。Qtツールキットは小さなAPIではありませんが、APIの高い割合(> 85%およびコア/ GUIパーツのほぼ100%)をカバーするために数百のクラスを生成できます。

HTH

于 2011-09-26T19:21:00.483 に答える
1

また、JNIをさまざまなオペレーティングシステムで動作させ、32/64ビットアーキテクチャに対処し、正しい共有ライブラリが検出されてロードされていることを確認するのに多くの問題がありました。CORBA(MICOとJacORB)も使いにくいと感じました。

C / C ++からJavaに呼び出す効果的な方法が見つかりませんでした。この状況での私の好ましい解決策は、Javaコードを次のいずれかとして実行することです。

  1. を使用してC/C++プログラムから簡単に実行できるスタンドアロンプ​​ログラムjava -cp myjar.jar org.foo.MyClass。これはあなたの状況には単純すぎると思います。

  2. ミニサーバーとして、TCP/IPソケットでC/C ++プログラムからの要求を受け入れ、このソケットを介して結果を返します。これには、ネットワークとシリアル化機能の記述が必要ですが、C / C ++プロセスとJavaプロセスを分離し、C++側またはJava側にある問題を明確に識別できます。

  3. Tomcatのサーブレットとして、C / C ++プログラムからHTTPリクエストを作成します(他のサーブレットコンテナも機能します)。これには、ネットワークおよびシリアル化機能の記述も必要です。これはSOAに似ています。

于 2011-09-26T23:40:07.207 に答える
1

ThriftまたはProtocolBuffersを使用してJavaからC++への呼び出しを容易にするのはどうですか?

于 2011-09-27T16:43:04.430 に答える
0

私自身の質問に答える:

http://java4cpp.kapott.org/

アクティブなプロジェクトではないようです。著者は、JDK1.5以降では使用しないことをお勧めします。

深刻な問題があるようです。ラッパーオブジェクトへのネイキッドポインタを渡します。

java::lang::Integer* i = new java::lang::Integer("10");

delete i; // don't forget to do this!

また、割り当ての互換性(たとえば、実装するインターフェイスのサブタイプとしてのクラス)を表すために、ラッパーが相互に継承する必要があるという、より微妙な問題が発生します。

于 2011-09-28T08:24:53.317 に答える
0

この釘には少し大きすぎるハンマーかもしれませんが、それがCORBAの目的ではありませんか?

于 2011-09-26T21:01:39.677 に答える
0

CORBAは希望どおりではないように思われるため、C /C++からJVMを起動する方法とJAVAメソッドを呼び出す方法を説明するリンクを次に示します。

http://java.sun.com/docs/books/jni/html/invoke.html および http://java.sys-con.com/node/45840

PS:JavaをC ++とインターフェースするときは、JNAまたはbridjも確認する必要があります。

于 2011-09-26T22:54:09.713 に答える