web-dev-qa-db-ja.com

C ++からJava)を呼び出す便利な方法を探しています

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自体は問題ありません。快適なインターフェイスが必要です。

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

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

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

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

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

[〜#〜]重要[〜#〜]

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

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

https://github.com/danielearwicker/cppjvm

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

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

31

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

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

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

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

16
Andy Thomas

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

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

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

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

8
Alexander Krapf

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

https://github.com/mo22/jnipp

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

4
Moritz

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

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

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

次に、C++コード(おそらく別のスレッドから)がセットアップされ、必要なすべての情報をブロックされて待機しているスレッドワーカーの1つに渡しますJavaスレッドワーカー、実行順序が与えられます。純粋な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

2
Darryl Miles

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

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

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

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

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

1
Simon C

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

1
MattRing

記事 Javaヒント17:JavaとC++ の統合)==はそれを行う方法を詳細に説明しています。

1

この釘には少し大きすぎるハンマーかもしれませんが、それは [〜#〜] corba [〜#〜] のために作られたものではありませんか?

0
Axel

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

http://Java.Sun.com/docs/books/jni/html/invoke.html および http://Java.sys-con.com/node/4584 ==

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

0
Axel

私自身の質問に答える:

http://Java4cpp.kapott.org/

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

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

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

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

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

0